Changeset 49:50a84c44cbf1 for wokkel
- Timestamp:
- Jan 12, 2009, 9:00:30 PM (13 years ago)
- Branch:
- default
- Convert:
- svn:b33ecbfc-034c-dc11-8662-000475d9059e/trunk@157
- Location:
- wokkel
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
wokkel/disco.py
r46 r49 1 1 # -*- test-case-name: wokkel.test.test_disco -*- 2 2 # 3 # Copyright (c) 2003-200 8Ralph Meijer3 # Copyright (c) 2003-2009 Ralph Meijer 4 4 # See LICENSE for details. 5 5 … … 12 12 13 13 from twisted.internet import defer 14 from twisted.words.protocols.jabber import error, jid 14 from twisted.words.protocols.jabber import error, jid, xmlstream 15 15 from twisted.words.xish import domish 16 16 17 from wokkel import data_form 17 18 from wokkel.iwokkel import IDisco 18 19 from wokkel.subprotocols import IQHandlerMixin, XMPPHandler … … 26 27 DISCO_ITEMS = IQ_GET + '/query[@xmlns="' + NS_DISCO_ITEMS + '"]' 27 28 28 class DiscoFeature(domish.Element): 29 """ 30 Element representing an XMPP service discovery feature. 31 """ 32 33 def __init__(self, feature): 34 domish.Element.__init__(self, (NS_DISCO_INFO, 'feature'), 35 attribs={'var': feature}) 36 37 38 class DiscoIdentity(domish.Element): 39 """ 40 Element representing an XMPP service discovery identity. 41 """ 42 43 def __init__(self, category, type, name = None): 44 domish.Element.__init__(self, (NS_DISCO_INFO, 'identity'), 45 attribs={'category': category, 46 'type': type}) 47 if name: 48 self['name'] = name 49 50 51 class DiscoItem(domish.Element): 52 """ 53 Element representing an XMPP service discovery item. 54 """ 55 56 def __init__(self, jid, node='', name=None): 57 domish.Element.__init__(self, (NS_DISCO_ITEMS, 'item'), 58 attribs={'jid': jid.full()}) 59 if node: 60 self['node'] = node 61 62 if name: 63 self['name'] = name 29 class DiscoFeature(unicode): 30 """ 31 XMPP service discovery feature. 32 33 This extends C{unicode} to convert to and from L{domish.Element}, but 34 further behaves identically. 35 """ 36 37 def toElement(self): 38 """ 39 Render to a DOM representation. 40 41 @rtype: L{domish.Element}. 42 """ 43 element = domish.Element((NS_DISCO_INFO, 'feature')) 44 element['var'] = unicode(self) 45 return element 46 47 48 @staticmethod 49 def fromElement(element): 50 """ 51 Parse a DOM representation into a L{DiscoFeature} instance. 52 53 @param element: Element that represents the disco feature. 54 @type element: L{domish.Element}. 55 @rtype L{DiscoFeature}. 56 """ 57 featureURI = element.getAttribute('var', u'') 58 feature = DiscoFeature(featureURI) 59 return feature 60 61 62 63 class DiscoIdentity(object): 64 """ 65 XMPP service discovery identity. 66 67 @ivar category: The identity category. 68 @type category: C{unicode} 69 @ivar type: The identity type. 70 @type type: C{unicode} 71 @ivar name: The optional natural language name for this entity. 72 @type name: C{unicode} 73 """ 74 75 def __init__(self, category, idType, name=None): 76 self.category = category 77 self.type = idType 78 self.name = name 79 80 81 def toElement(self): 82 """ 83 Generate a DOM representation. 84 85 @rtype: L{domish.Element}. 86 """ 87 element = domish.Element((NS_DISCO_INFO, 'identity')) 88 if self.category: 89 element['category'] = self.category 90 if self.type: 91 element['type'] = self.type 92 if self.name: 93 element['name'] = self.name 94 return element 95 96 97 @staticmethod 98 def fromElement(element): 99 """ 100 Parse a DOM representation into a L{DiscoIdentity} instance. 101 102 @param element: Element that represents the disco identity. 103 @type element: L{domish.Element}. 104 @rtype L{DiscoIdentity}. 105 """ 106 category = element.getAttribute('category') 107 idType = element.getAttribute('type') 108 name = element.getAttribute('name') 109 feature = DiscoIdentity(category, idType, name) 110 return feature 111 112 113 114 class DiscoInfo(object): 115 """ 116 XMPP service discovery info. 117 118 @ivar nodeIdentifier: The optional node this info applies to. 119 @type nodeIdentifier: C{unicode} 120 @ivar features: Features as L{DiscoFeature}. 121 @type features: C{set) 122 @ivar identities: Identities as a mapping from (category, type) to name, 123 all C{unicode}. 124 @type identities: C{dict} 125 @ivar extensions: Service discovery extensions as a mapping from the 126 extension form's C{FORM_TYPE} (C{unicode}) to 127 L{data_form.Form}. Forms with no C{FORM_TYPE} field 128 are mapped as C{None}. Note that multiple forms 129 with the same C{FORM_TYPE} have the last in sequence 130 prevail. 131 @type extensions: C{dict} 132 @ivar _items: Sequence of added items. 133 @type _items: C{list} 134 """ 135 136 def __init__(self): 137 self.nodeIdentifier = '' 138 self.features = set() 139 self.identities = {} 140 self.extensions = {} 141 self._items = [] 142 143 144 def __iter__(self): 145 """ 146 Iterator over sequence of items in the order added. 147 """ 148 return iter(self._items) 149 150 151 def append(self, item): 152 """ 153 Add a piece of service discovery info. 154 155 @param item: A feature, identity or extension form. 156 @type item: L{DiscoFeature}, L{DiscoIdentity} or L{data_form.Form} 157 """ 158 self._items.append(item) 159 160 if isinstance(item, DiscoFeature): 161 self.features.add(item) 162 elif isinstance(item, DiscoIdentity): 163 self.identities[(item.category, item.type)] = item.name 164 elif isinstance(item, data_form.Form): 165 self.extensions[item.formNamespace] = item 166 167 168 def toElement(self): 169 """ 170 Generate a DOM representation. 171 172 This takes the items added with C{append} to create a DOM 173 representation of service discovery information. 174 175 @rtype: L{domish.Element}. 176 """ 177 element = domish.Element((NS_DISCO_INFO, 'query')) 178 179 if self.nodeIdentifier: 180 element['node'] = self.nodeIdentifier 181 182 for item in self: 183 element.addChild(item.toElement()) 184 185 return element 186 187 188 @staticmethod 189 def fromElement(element): 190 """ 191 Parse a DOM representation into a L{DiscoInfo} instance. 192 193 @param element: Element that represents the disco info. 194 @type element: L{domish.Element}. 195 @rtype L{DiscoInfo}. 196 """ 197 198 info = DiscoInfo() 199 200 info.nodeIdentifier = element.getAttribute('node', '') 201 202 for child in element.elements(): 203 item = None 204 205 if (child.uri, child.name) == (NS_DISCO_INFO, 'feature'): 206 item = DiscoFeature.fromElement(child) 207 elif (child.uri, child.name) == (NS_DISCO_INFO, 'identity'): 208 item = DiscoIdentity.fromElement(child) 209 elif (child.uri, child.name) == (data_form.NS_X_DATA, 'x'): 210 item = data_form.Form.fromElement(child) 211 212 if item: 213 info.append(item) 214 215 return info 216 217 218 219 class DiscoItem(object): 220 """ 221 XMPP service discovery item. 222 223 @ivar entity: The entity holding the item. 224 @type entity: L{jid.JID} 225 @ivar nodeIdentifier: The optional node identifier for the item. 226 @type nodeIdentifier: C{unicode} 227 @ivar name: The optional natural language name for this entity. 228 @type name: C{unicode} 229 """ 230 231 def __init__(self, entity, nodeIdentifier='', name=None): 232 self.entity = entity 233 self.nodeIdentifier = nodeIdentifier 234 self.name = name 235 236 237 def toElement(self): 238 """ 239 Generate a DOM representation. 240 241 @rtype: L{domish.Element}. 242 """ 243 element = domish.Element((NS_DISCO_ITEMS, 'item')) 244 if self.entity: 245 element['jid'] = self.entity.full() 246 if self.nodeIdentifier: 247 element['node'] = self.nodeIdentifier 248 if self.name: 249 element['name'] = self.name 250 return element 251 252 253 @staticmethod 254 def fromElement(element): 255 """ 256 Parse a DOM representation into a L{DiscoItem} instance. 257 258 @param element: Element that represents the disco iitem. 259 @type element: L{domish.Element}. 260 @rtype L{DiscoItem}. 261 """ 262 try: 263 entity = jid.JID(element.getAttribute('jid', ' ')) 264 except jid.InvalidFormat: 265 entity = None 266 nodeIdentifier = element.getAttribute('node', '') 267 name = element.getAttribute('name') 268 feature = DiscoItem(entity, nodeIdentifier, name) 269 return feature 270 271 272 273 class DiscoItems(object): 274 """ 275 XMPP service discovery items. 276 277 @ivar nodeIdentifier: The optional node this info applies to. 278 @type nodeIdentifier: C{unicode} 279 @ivar _items: Sequence of added items. 280 @type _items: C{list} 281 """ 282 283 def __init__(self): 284 self.nodeIdentifier = '' 285 self._items = [] 286 287 288 def __iter__(self): 289 """ 290 Iterator over sequence of items in the order added. 291 """ 292 return iter(self._items) 293 294 295 def append(self, item): 296 """ 297 Append item to the sequence of items. 298 299 @param item: Item to be added. 300 @type item: L{DiscoItem} 301 """ 302 self._items.append(item) 303 304 305 def toElement(self): 306 """ 307 Generate a DOM representation. 308 309 This takes the items added with C{append} to create a DOM 310 representation of service discovery items. 311 312 @rtype: L{domish.Element}. 313 """ 314 element = domish.Element((NS_DISCO_ITEMS, 'query')) 315 316 if self.nodeIdentifier: 317 element['node'] = self.nodeIdentifier 318 319 for item in self: 320 element.addChild(item.toElement()) 321 322 return element 323 324 325 @staticmethod 326 def fromElement(element): 327 """ 328 Parse a DOM representation into a L{DiscoItems} instance. 329 330 @param element: Element that represents the disco items. 331 @type element: L{domish.Element}. 332 @rtype L{DiscoItems}. 333 """ 334 335 info = DiscoItems() 336 337 info.nodeIdentifier = element.getAttribute('node', '') 338 339 for child in element.elements(): 340 if (child.uri, child.name) == (NS_DISCO_ITEMS, 'item'): 341 item = DiscoItem.fromElement(child) 342 info.append(item) 343 344 return info 345 346 347 348 class _DiscoRequest(xmlstream.IQ): 349 """ 350 Element representing an XMPP service discovery request. 351 """ 352 353 def __init__(self, xs, namespace, nodeIdentifier=''): 354 """ 355 Initialize the request. 356 357 @param xs: XML Stream the request should go out on. 358 @type xs: L{xmlstream.XmlStream} 359 @param namespace: Request namespace. 360 @type namespace: C{str} 361 @param nodeIdentifier: Node to request info from. 362 @type nodeIdentifier: C{unicode} 363 """ 364 xmlstream.IQ.__init__(self, xs, "get") 365 query = self.addElement((namespace, 'query')) 366 if nodeIdentifier: 367 query['node'] = nodeIdentifier 368 369 370 371 class DiscoClientProtocol(XMPPHandler): 372 """ 373 XMPP Service Discovery client protocol. 374 """ 375 376 def requestInfo(self, entity, nodeIdentifier=''): 377 """ 378 Request information discovery from a node. 379 380 @param entity: Entity to send the request to. 381 @type entity: L{jid.JID} 382 @param nodeIdentifier: Optional node to request info from. 383 @type nodeIdentifier: C{unicode} 384 """ 385 386 request = _DiscoRequest(self.xmlstream, NS_DISCO_INFO, nodeIdentifier) 387 388 d = request.send(entity.full()) 389 d.addCallback(lambda iq: DiscoInfo.fromElement(iq.query)) 390 return d 391 392 393 def requestItems(self, entity, nodeIdentifier=''): 394 """ 395 Request items discovery from a node. 396 397 @param entity: Entity to send the request to. 398 @type entity: L{jid.JID} 399 @param nodeIdentifier: Optional node to request info from. 400 @type nodeIdentifier: C{unicode} 401 """ 402 403 request = _DiscoRequest(self.xmlstream, NS_DISCO_ITEMS, nodeIdentifier) 404 405 d = request.send(entity.full()) 406 d.addCallback(lambda iq: DiscoItems.fromElement(iq.query)) 407 return d 64 408 65 409 … … 97 441 raise error.StanzaError('item-not-found') 98 442 else: 99 response = domish.Element((NS_DISCO_INFO, 'query')) 100 if nodeIdentifier: 101 response['node'] = nodeIdentifier 443 response = DiscoInfo() 444 response.nodeIdentifier = nodeIdentifier 102 445 103 446 for item in info: 104 response.a ddChild(item)105 106 return response 447 response.append(item) 448 449 return response.toElement() 107 450 108 451 d = self.info(requestor, target, nodeIdentifier) … … 123 466 124 467 def toResponse(items): 125 response = domish.Element((NS_DISCO_ITEMS, 'query')) 126 if nodeIdentifier: 127 response['node'] = nodeIdentifier 468 response = DiscoItems() 469 response.nodeIdentifier = nodeIdentifier 128 470 129 471 for item in items: 130 response.a ddChild(item)131 132 return response 472 response.append(item) 473 474 return response.toElement() 133 475 134 476 d = self.items(requestor, target, nodeIdentifier) -
wokkel/pubsub.py
r47 r49 541 541 542 542 if not nodeIdentifier: 543 info.append(disco.DiscoIdentity(**self.discoIdentity)) 543 category, idType, name = self.discoIdentity 544 info.append(disco.DiscoIdentity(category, idType, name)) 544 545 545 546 info.append(disco.DiscoFeature(disco.NS_DISCO_ITEMS)) -
wokkel/test/test_disco.py
r46 r49 1 # Copyright (c) 2003-200 8Ralph Meijer1 # Copyright (c) 2003-2009 Ralph Meijer 2 2 # See LICENSE for details. 3 3 … … 6 6 """ 7 7 8 from zope.interface import implements 9 8 10 from twisted.internet import defer 9 11 from twisted.trial import unittest 10 12 from twisted.words.protocols.jabber.jid import JID 11 from zope.interface import implements 12 13 from wokkel import disco 13 from twisted.words.xish import domish 14 15 from wokkel import data_form, disco 16 from wokkel.generic import parseXml 14 17 from wokkel.subprotocols import XMPPHandler 15 from wokkel.test.helpers import TestableRequestHandlerMixin 16 18 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub 19 20 try: 21 from twisted.words.protocols.jabber.xmlstream import toResponse 22 except ImportError: 23 from wokkel.compat import toResponse 17 24 18 25 NS_DISCO_INFO = 'http://jabber.org/protocol/disco#info' 19 26 NS_DISCO_ITEMS = 'http://jabber.org/protocol/disco#items' 27 28 class DiscoFeatureTest(unittest.TestCase): 29 """ 30 Tests for L{disco.DiscoFeature}. 31 """ 32 33 def test_init(self): 34 """ 35 Test initialization with a with feature namespace URI. 36 """ 37 feature = disco.DiscoFeature(u'testns') 38 self.assertEqual(u'testns', feature) 39 40 41 def test_toElement(self): 42 """ 43 Test proper rendering to a DOM representation. 44 45 The returned element should be properly named and have a C{var} 46 attribute that holds the feature namespace URI. 47 """ 48 feature = disco.DiscoFeature(u'testns') 49 element = feature.toElement() 50 self.assertEqual(NS_DISCO_INFO, element.uri) 51 self.assertEqual(u'feature', element.name) 52 self.assertTrue(element.hasAttribute(u'var')) 53 self.assertEqual(u'testns', element[u'var']) 54 55 56 def test_fromElement(self): 57 """ 58 Test creating L{disco.DiscoFeature} from L{domish.Element}. 59 """ 60 element = domish.Element((NS_DISCO_INFO, u'feature')) 61 element['var'] = u'testns' 62 feature = disco.DiscoFeature.fromElement(element) 63 self.assertEqual(u'testns', feature) 64 65 66 67 class DiscoIdentityTest(unittest.TestCase): 68 """ 69 Tests for L{disco.DiscoIdentity}. 70 """ 71 72 def test_init(self): 73 """ 74 Test initialization with a category, type and name. 75 """ 76 identity = disco.DiscoIdentity(u'conference', u'text', u'The chatroom') 77 self.assertEqual(u'conference', identity.category) 78 self.assertEqual(u'text', identity.type) 79 self.assertEqual(u'The chatroom', identity.name) 80 81 82 def test_toElement(self): 83 """ 84 Test proper rendering to a DOM representation. 85 86 The returned element should be properly named and have C{conference}, 87 C{type}, and C{name} attributes. 88 """ 89 identity = disco.DiscoIdentity(u'conference', u'text', u'The chatroom') 90 element = identity.toElement() 91 self.assertEqual(NS_DISCO_INFO, element.uri) 92 self.assertEqual(u'identity', element.name) 93 self.assertEqual(u'conference', element.getAttribute(u'category')) 94 self.assertEqual(u'text', element.getAttribute(u'type')) 95 self.assertEqual(u'The chatroom', element.getAttribute(u'name')) 96 97 98 def test_toElementWithoutName(self): 99 """ 100 Test proper rendering to a DOM representation without a name. 101 102 The returned element should be properly named and have C{conference}, 103 C{type} attributes, no C{name} attribute. 104 """ 105 identity = disco.DiscoIdentity(u'conference', u'text') 106 element = identity.toElement() 107 self.assertEqual(NS_DISCO_INFO, element.uri) 108 self.assertEqual(u'identity', element.name) 109 self.assertEqual(u'conference', element.getAttribute(u'category')) 110 self.assertEqual(u'text', element.getAttribute(u'type')) 111 self.assertFalse(element.hasAttribute(u'name')) 112 113 114 def test_fromElement(self): 115 """ 116 Test creating L{disco.DiscoIdentity} from L{domish.Element}. 117 """ 118 element = domish.Element((NS_DISCO_INFO, u'identity')) 119 element['category'] = u'conference' 120 element['type'] = u'text' 121 element['name'] = u'The chatroom' 122 identity = disco.DiscoIdentity.fromElement(element) 123 self.assertEqual(u'conference', identity.category) 124 self.assertEqual(u'text', identity.type) 125 self.assertEqual(u'The chatroom', identity.name) 126 127 128 def test_fromElementWithoutName(self): 129 """ 130 Test creating L{disco.DiscoIdentity} from L{domish.Element}, no name. 131 """ 132 element = domish.Element((NS_DISCO_INFO, u'identity')) 133 element['category'] = u'conference' 134 element['type'] = u'text' 135 identity = disco.DiscoIdentity.fromElement(element) 136 self.assertEqual(u'conference', identity.category) 137 self.assertEqual(u'text', identity.type) 138 self.assertEqual(None, identity.name) 139 140 141 142 class DiscoInfoTest(unittest.TestCase): 143 """ 144 Tests for L{disco.DiscoInfo}. 145 """ 146 147 def test_toElement(self): 148 """ 149 Test C{toElement} creates a correctly namespaced element, no node. 150 """ 151 info = disco.DiscoInfo() 152 element = info.toElement() 153 154 self.assertEqual(NS_DISCO_INFO, element.uri) 155 self.assertEqual(u'query', element.name) 156 self.assertFalse(element.hasAttribute(u'node')) 157 158 159 def test_toElementNode(self): 160 """ 161 Test C{toElement} with a node. 162 """ 163 info = disco.DiscoInfo() 164 info.nodeIdentifier = u'test' 165 element = info.toElement() 166 167 self.assertEqual(u'test', element.getAttribute(u'node')) 168 169 170 def test_toElementChildren(self): 171 """ 172 Test C{toElement} creates a DOM with proper childs. 173 """ 174 info = disco.DiscoInfo() 175 info.append(disco.DiscoFeature(u'jabber:iq:register')) 176 info.append(disco.DiscoIdentity(u'conference', u'text')) 177 info.append(data_form.Form(u'result')) 178 element = info.toElement() 179 180 featureElements = domish.generateElementsQNamed(element.children, 181 u'feature', 182 NS_DISCO_INFO) 183 self.assertEqual(1, len(list(featureElements))) 184 185 identityElements = domish.generateElementsQNamed(element.children, 186 u'identity', 187 NS_DISCO_INFO) 188 self.assertEqual(1, len(list(identityElements))) 189 190 extensionElements = domish.generateElementsQNamed(element.children, 191 u'x', 192 data_form.NS_X_DATA) 193 self.assertEqual(1, len(list(extensionElements))) 194 195 196 def test_fromElement(self): 197 """ 198 Test properties when creating L{disco.DiscoInfo} from L{domish.Element}. 199 """ 200 xml = """<query xmlns='http://jabber.org/protocol/disco#info'> 201 <identity category='conference' 202 type='text' 203 name='A Dark Cave'/> 204 <feature var='http://jabber.org/protocol/muc'/> 205 <feature var='jabber:iq:register'/> 206 <x xmlns='jabber:x:data' type='result'> 207 <field var='FORM_TYPE' type='hidden'> 208 <value>http://jabber.org/protocol/muc#roominfo</value> 209 </field> 210 </x> 211 </query>""" 212 213 element = parseXml(xml) 214 info = disco.DiscoInfo.fromElement(element) 215 216 self.assertIn(u'http://jabber.org/protocol/muc', info.features) 217 self.assertIn(u'jabber:iq:register', info.features) 218 219 self.assertIn((u'conference', u'text'), info.identities) 220 self.assertEqual(u'A Dark Cave', 221 info.identities[(u'conference', u'text')]) 222 223 self.assertIn(u'http://jabber.org/protocol/muc#roominfo', 224 info.extensions) 225 226 227 def test_fromElementItems(self): 228 """ 229 Test items when creating L{disco.DiscoInfo} from L{domish.Element}. 230 """ 231 xml = """<query xmlns='http://jabber.org/protocol/disco#info'> 232 <identity category='conference' 233 type='text' 234 name='A Dark Cave'/> 235 <feature var='http://jabber.org/protocol/muc'/> 236 <feature var='jabber:iq:register'/> 237 <x xmlns='jabber:x:data' type='result'> 238 <field var='FORM_TYPE' type='hidden'> 239 <value>http://jabber.org/protocol/muc#roominfo</value> 240 </field> 241 </x> 242 </query>""" 243 244 element = parseXml(xml) 245 info = disco.DiscoInfo.fromElement(element) 246 247 info = list(info) 248 self.assertEqual(4, len(info)) 249 250 identity = info[0] 251 self.assertEqual(u'conference', identity.category) 252 253 self.assertEqual(u'http://jabber.org/protocol/muc', info[1]) 254 self.assertEqual(u'jabber:iq:register', info[2]) 255 256 extension = info[3] 257 self.assertEqual(u'http://jabber.org/protocol/muc#roominfo', 258 extension.formNamespace) 259 260 261 def test_fromElementNoNode(self): 262 """ 263 Test creating L{disco.DiscoInfo} from L{domish.Element}, no node. 264 """ 265 xml = """<query xmlns='http://jabber.org/protocol/disco#info'/>""" 266 267 element = parseXml(xml) 268 info = disco.DiscoInfo.fromElement(element) 269 270 self.assertEqual(u'', info.nodeIdentifier) 271 272 273 def test_fromElementNode(self): 274 """ 275 Test creating L{disco.DiscoInfo} from L{domish.Element}, with node. 276 """ 277 xml = """<query xmlns='http://jabber.org/protocol/disco#info' 278 node='test'> 279 </query>""" 280 281 element = parseXml(xml) 282 info = disco.DiscoInfo.fromElement(element) 283 284 self.assertEqual(u'test', info.nodeIdentifier) 285 286 287 288 class DiscoItemTest(unittest.TestCase): 289 """ 290 Tests for L{disco.DiscoItem}. 291 """ 292 293 def test_init(self): 294 """ 295 Test initialization with a category, type and name. 296 """ 297 item = disco.DiscoItem(JID(u'example.org'), u'test', u'The node') 298 self.assertEqual(JID(u'example.org'), item.entity) 299 self.assertEqual(u'test', item.nodeIdentifier) 300 self.assertEqual(u'The node', item.name) 301 302 303 def test_toElement(self): 304 """ 305 Test proper rendering to a DOM representation. 306 307 The returned element should be properly named and have C{jid}, C{node}, 308 and C{name} attributes. 309 """ 310 item = disco.DiscoItem(JID(u'example.org'), u'test', u'The node') 311 element = item.toElement() 312 self.assertEqual(NS_DISCO_ITEMS, element.uri) 313 self.assertEqual(u'item', element.name) 314 self.assertEqual(u'example.org', element.getAttribute(u'jid')) 315 self.assertEqual(u'test', element.getAttribute(u'node')) 316 self.assertEqual(u'The node', element.getAttribute(u'name')) 317 318 319 def test_toElementWithoutName(self): 320 """ 321 Test proper rendering to a DOM representation without a name. 322 323 The returned element should be properly named and have C{jid}, C{node} 324 attributes, no C{name} attribute. 325 """ 326 item = disco.DiscoItem(JID(u'example.org'), u'test') 327 element = item.toElement() 328 self.assertEqual(NS_DISCO_ITEMS, element.uri) 329 self.assertEqual(u'item', element.name) 330 self.assertEqual(u'example.org', element.getAttribute(u'jid')) 331 self.assertEqual(u'test', element.getAttribute(u'node')) 332 self.assertFalse(element.hasAttribute(u'name')) 333 334 335 def test_fromElement(self): 336 """ 337 Test creating L{disco.DiscoItem} from L{domish.Element}. 338 """ 339 element = domish.Element((NS_DISCO_ITEMS, u'item')) 340 element[u'jid'] = u'example.org' 341 element[u'node'] = u'test' 342 element[u'name'] = u'The node' 343 item = disco.DiscoItem.fromElement(element) 344 self.assertEqual(JID(u'example.org'), item.entity) 345 self.assertEqual(u'test', item.nodeIdentifier) 346 self.assertEqual(u'The node', item.name) 347 348 def test_fromElementNoNode(self): 349 """ 350 Test creating L{disco.DiscoItem} from L{domish.Element}, no node. 351 """ 352 element = domish.Element((NS_DISCO_ITEMS, u'item')) 353 element[u'jid'] = u'example.org' 354 element[u'name'] = u'The node' 355 item = disco.DiscoItem.fromElement(element) 356 self.assertEqual(JID(u'example.org'), item.entity) 357 self.assertEqual(u'', item.nodeIdentifier) 358 self.assertEqual(u'The node', item.name) 359 360 361 def test_fromElementNoName(self): 362 """ 363 Test creating L{disco.DiscoItem} from L{domish.Element}, no name. 364 """ 365 element = domish.Element((NS_DISCO_ITEMS, u'item')) 366 element[u'jid'] = u'example.org' 367 element[u'node'] = u'test' 368 item = disco.DiscoItem.fromElement(element) 369 self.assertEqual(JID(u'example.org'), item.entity) 370 self.assertEqual(u'test', item.nodeIdentifier) 371 self.assertEqual(None, item.name) 372 373 def test_fromElementBadJID(self): 374 """ 375 Test creating L{disco.DiscoItem} from L{domish.Element}, bad JID. 376 """ 377 element = domish.Element((NS_DISCO_ITEMS, u'item')) 378 element[u'jid'] = u'ex@@@ample.org' 379 item = disco.DiscoItem.fromElement(element) 380 self.assertIdentical(None, item.entity) 381 382 383 384 class DiscoItemsTest(unittest.TestCase): 385 """ 386 Tests for L{disco.DiscoItems}. 387 """ 388 389 def test_toElement(self): 390 """ 391 Test C{toElement} creates a correctly namespaced element, no node. 392 """ 393 items = disco.DiscoItems() 394 element = items.toElement() 395 396 self.assertEqual(NS_DISCO_ITEMS, element.uri) 397 self.assertEqual(u'query', element.name) 398 self.assertFalse(element.hasAttribute(u'node')) 399 400 401 def test_toElementNode(self): 402 """ 403 Test C{toElement} with a node. 404 """ 405 items = disco.DiscoItems() 406 items.nodeIdentifier = u'test' 407 element = items.toElement() 408 409 self.assertEqual(u'test', element.getAttribute(u'node')) 410 411 412 def test_toElementChildren(self): 413 """ 414 Test C{toElement} creates a DOM with proper childs. 415 """ 416 items = disco.DiscoItems() 417 items.append(disco.DiscoItem(JID(u'example.org'), u'test', u'A node')) 418 element = items.toElement() 419 420 itemElements = domish.generateElementsQNamed(element.children, 421 u'item', 422 NS_DISCO_ITEMS) 423 self.assertEqual(1, len(list(itemElements))) 424 425 426 def test_fromElement(self): 427 """ 428 Test creating L{disco.DiscoItems} from L{domish.Element}. 429 """ 430 xml = """<query xmlns='http://jabber.org/protocol/disco#items'> 431 <item jid='example.org' node='test' name='A node'/> 432 </query>""" 433 434 element = parseXml(xml) 435 items = disco.DiscoItems.fromElement(element) 436 437 items = list(items) 438 self.assertEqual(1, len(items)) 439 item = items[0] 440 441 self.assertEqual(JID(u'example.org'), item.entity) 442 self.assertEqual(u'test', item.nodeIdentifier) 443 self.assertEqual(u'A node', item.name) 444 445 446 def test_fromElementNoNode(self): 447 """ 448 Test creating L{disco.DiscoItems} from L{domish.Element}, no node. 449 """ 450 xml = """<query xmlns='http://jabber.org/protocol/disco#items'/>""" 451 452 element = parseXml(xml) 453 items = disco.DiscoItems.fromElement(element) 454 455 self.assertEqual(u'', items.nodeIdentifier) 456 457 458 def test_fromElementNode(self): 459 """ 460 Test creating L{disco.DiscoItems} from L{domish.Element}, with node. 461 """ 462 xml = """<query xmlns='http://jabber.org/protocol/disco#items' 463 node='test'> 464 </query>""" 465 466 element = parseXml(xml) 467 items = disco.DiscoItems.fromElement(element) 468 469 self.assertEqual(u'test', items.nodeIdentifier) 470 471 472 473 class DiscoClientProtocolTest(unittest.TestCase): 474 """ 475 Tests for L{disco.DiscoClientProtocol}. 476 """ 477 478 def setUp(self): 479 """ 480 Set up stub and protocol for testing. 481 """ 482 self.stub = XmlStreamStub() 483 self.protocol = disco.DiscoClientProtocol() 484 self.protocol.xmlstream = self.stub.xmlstream 485 self.protocol.connectionInitialized() 486 487 488 def test_requestItems(self): 489 """ 490 Test request sent out by C{requestItems} and parsing of response. 491 """ 492 def cb(items): 493 items = list(items) 494 self.assertEqual(2, len(items)) 495 self.assertEqual(JID(u'test.example.org'), items[0].entity) 496 497 d = self.protocol.requestItems(JID(u'example.org'),u"foo") 498 d.addCallback(cb) 499 500 iq = self.stub.output[-1] 501 self.assertEqual(u'example.org', iq.getAttribute(u'to')) 502 self.assertEqual(u'get', iq.getAttribute(u'type')) 503 self.assertEqual(u'foo', iq.query.getAttribute(u'node')) 504 self.assertEqual(NS_DISCO_ITEMS, iq.query.uri) 505 506 response = toResponse(iq, u'result') 507 query = response.addElement((NS_DISCO_ITEMS, u'query')) 508 509 element = query.addElement(u'item') 510 element[u'jid'] = u'test.example.org' 511 element[u'node'] = u'music' 512 element[u'name'] = u'Music from the time of Shakespeare' 513 514 element = query.addElement(u'item') 515 element[u'jid'] = u"test2.example.org" 516 517 self.stub.send(response) 518 return d 519 520 521 def test_requestInfo(self): 522 """ 523 Test request sent out by C{requestInfo} and parsing of response. 524 """ 525 def cb(info): 526 self.assertIn((u'conference', u'text'), info.identities) 527 self.assertIn(u'http://jabber.org/protocol/disco#info', 528 info.features) 529 self.assertIn(u'http://jabber.org/protocol/muc', 530 info.features) 531 532 d = self.protocol.requestInfo(JID(u'example.org'),'foo') 533 d.addCallback(cb) 534 535 iq = self.stub.output[-1] 536 self.assertEqual(u'example.org', iq.getAttribute(u'to')) 537 self.assertEqual(u'get', iq.getAttribute(u'type')) 538 self.assertEqual(u'foo', iq.query.getAttribute(u'node')) 539 self.assertEqual(NS_DISCO_INFO, iq.query.uri) 540 541 response = toResponse(iq, u'result') 542 query = response.addElement((NS_DISCO_INFO, u'query')) 543 544 element = query.addElement(u"identity") 545 element[u'category'] = u'conference' # required 546 element[u'type'] = u'text' # required 547 element[u"name"] = u'Romeo and Juliet, Act II, Scene II' # optional 548 549 element = query.addElement("feature") 550 element[u'var'] = u'http://jabber.org/protocol/disco#info' # required 551 552 element = query.addElement(u"feature") 553 element[u'var'] = u'http://jabber.org/protocol/muc' 554 555 self.stub.send(response) 556 return d 557 20 558 21 559 … … 67 605 return d 68 606 607 69 608 def test_onDiscoInfoWithNode(self): 70 609 """ … … 128 667 return d 129 668 669 130 670 def test_onDiscoItemsWithNode(self): 131 671 """
Note: See TracChangeset
for help on using the changeset viewer.