1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Tests for L{twisted.words.protocols.jabber.error}.
8 from twisted.trial import unittest
10 from twisted.words.protocols.jabber import error
11 from twisted.words.xish import domish
13 NS_XML = 'http://www.w3.org/XML/1998/namespace'
14 NS_STREAMS = 'http://etherx.jabber.org/streams'
15 NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams'
16 NS_XMPP_STANZAS = 'urn:ietf:params:xml:ns:xmpp-stanzas'
18 class BaseErrorTest(unittest.TestCase):
20 def test_getElementPlain(self):
22 Test getting an element for a plain error.
24 e = error.BaseError('feature-not-implemented')
25 element = e.getElement()
26 self.assertIdentical(element.uri, None)
27 self.assertEqual(len(element.children), 1)
29 def test_getElementText(self):
31 Test getting an element for an error with a text.
33 e = error.BaseError('feature-not-implemented', 'text')
34 element = e.getElement()
35 self.assertEqual(len(element.children), 2)
36 self.assertEqual(unicode(element.text), 'text')
37 self.assertEqual(element.text.getAttribute((NS_XML, 'lang')), None)
39 def test_getElementTextLang(self):
41 Test getting an element for an error with a text and language.
43 e = error.BaseError('feature-not-implemented', 'text', 'en_US')
44 element = e.getElement()
45 self.assertEqual(len(element.children), 2)
46 self.assertEqual(unicode(element.text), 'text')
47 self.assertEqual(element.text[(NS_XML, 'lang')], 'en_US')
49 def test_getElementAppCondition(self):
51 Test getting an element for an error with an app specific condition.
53 ac = domish.Element(('testns', 'myerror'))
54 e = error.BaseError('feature-not-implemented', appCondition=ac)
55 element = e.getElement()
56 self.assertEqual(len(element.children), 2)
57 self.assertEqual(element.myerror, ac)
59 class StreamErrorTest(unittest.TestCase):
61 def test_getElementPlain(self):
63 Test namespace of the element representation of an error.
65 e = error.StreamError('feature-not-implemented')
66 element = e.getElement()
67 self.assertEqual(element.uri, NS_STREAMS)
69 def test_getElementConditionNamespace(self):
71 Test that the error condition element has the correct namespace.
73 e = error.StreamError('feature-not-implemented')
74 element = e.getElement()
75 self.assertEqual(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri)
77 def test_getElementTextNamespace(self):
79 Test that the error text element has the correct namespace.
81 e = error.StreamError('feature-not-implemented', 'text')
82 element = e.getElement()
83 self.assertEqual(NS_XMPP_STREAMS, element.text.uri)
87 class StanzaErrorTest(unittest.TestCase):
89 Tests for L{error.StreamError}.
93 def test_typeRemoteServerTimeout(self):
95 Remote Server Timeout should yield type wait, code 504.
97 e = error.StanzaError('remote-server-timeout')
98 self.assertEqual('wait', e.type)
99 self.assertEqual('504', e.code)
102 def test_getElementPlain(self):
104 Test getting an element for a plain stanza error.
106 e = error.StanzaError('feature-not-implemented')
107 element = e.getElement()
108 self.assertEqual(element.uri, None)
109 self.assertEqual(element['type'], 'cancel')
110 self.assertEqual(element['code'], '501')
113 def test_getElementType(self):
115 Test getting an element for a stanza error with a given type.
117 e = error.StanzaError('feature-not-implemented', 'auth')
118 element = e.getElement()
119 self.assertEqual(element.uri, None)
120 self.assertEqual(element['type'], 'auth')
121 self.assertEqual(element['code'], '501')
124 def test_getElementConditionNamespace(self):
126 Test that the error condition element has the correct namespace.
128 e = error.StanzaError('feature-not-implemented')
129 element = e.getElement()
130 self.assertEqual(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri)
133 def test_getElementTextNamespace(self):
135 Test that the error text element has the correct namespace.
137 e = error.StanzaError('feature-not-implemented', text='text')
138 element = e.getElement()
139 self.assertEqual(NS_XMPP_STANZAS, element.text.uri)
142 def test_toResponse(self):
144 Test an error response is generated from a stanza.
146 The addressing on the (new) response stanza should be reversed, an
147 error child (with proper properties) added and the type set to
150 stanza = domish.Element(('jabber:client', 'message'))
151 stanza['type'] = 'chat'
152 stanza['to'] = 'user1@example.com'
153 stanza['from'] = 'user2@example.com/resource'
154 e = error.StanzaError('service-unavailable')
155 response = e.toResponse(stanza)
156 self.assertNotIdentical(response, stanza)
157 self.assertEqual(response['from'], 'user1@example.com')
158 self.assertEqual(response['to'], 'user2@example.com/resource')
159 self.assertEqual(response['type'], 'error')
160 self.assertEqual(response.error.children[0].name,
161 'service-unavailable')
162 self.assertEqual(response.error['type'], 'cancel')
163 self.assertNotEqual(stanza.children, response.children)
167 class ParseErrorTest(unittest.TestCase):
169 Tests for L{error._parseError}.
174 self.error = domish.Element((None, 'error'))
177 def test_empty(self):
179 Test parsing of the empty error element.
181 result = error._parseError(self.error, 'errorns')
182 self.assertEqual({'condition': None,
185 'appCondition': None}, result)
188 def test_condition(self):
190 Test parsing of an error element with a condition.
192 self.error.addElement(('errorns', 'bad-request'))
193 result = error._parseError(self.error, 'errorns')
194 self.assertEqual('bad-request', result['condition'])
199 Test parsing of an error element with a text.
201 text = self.error.addElement(('errorns', 'text'))
202 text.addContent('test')
203 result = error._parseError(self.error, 'errorns')
204 self.assertEqual('test', result['text'])
205 self.assertEqual(None, result['textLang'])
208 def test_textLang(self):
210 Test parsing of an error element with a text with a defined language.
212 text = self.error.addElement(('errorns', 'text'))
213 text[NS_XML, 'lang'] = 'en_US'
214 text.addContent('test')
215 result = error._parseError(self.error, 'errorns')
216 self.assertEqual('en_US', result['textLang'])
219 def test_textLangInherited(self):
221 Test parsing of an error element with a text with inherited language.
223 text = self.error.addElement(('errorns', 'text'))
224 self.error[NS_XML, 'lang'] = 'en_US'
225 text.addContent('test')
226 result = error._parseError(self.error, 'errorns')
227 self.assertEqual('en_US', result['textLang'])
228 test_textLangInherited.todo = "xml:lang inheritance not implemented"
231 def test_appCondition(self):
233 Test parsing of an error element with an app specific condition.
235 condition = self.error.addElement(('testns', 'condition'))
236 result = error._parseError(self.error, 'errorns')
237 self.assertEqual(condition, result['appCondition'])
240 def test_appConditionMultiple(self):
242 Test parsing of an error element with multiple app specific conditions.
244 self.error.addElement(('testns', 'condition'))
245 condition = self.error.addElement(('testns', 'condition2'))
246 result = error._parseError(self.error, 'errorns')
247 self.assertEqual(condition, result['appCondition'])
251 class ExceptionFromStanzaTest(unittest.TestCase):
253 def test_basic(self):
255 Test basic operations of exceptionFromStanza.
257 Given a realistic stanza, check if a sane exception is returned.
262 from='pubsub.shakespeare.lit'
263 to='francisco@denmark.lit/barracks'
265 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
268 <error type='cancel'>
269 <feature-not-implemented
270 xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
271 <unsupported xmlns='http://jabber.org/protocol/pubsub#errors'
272 feature='retrieve-subscriptions'/>
277 stanza = domish.Element((None, 'stanza'))
278 p = stanza.addElement(('http://jabber.org/protocol/pubsub', 'pubsub'))
279 p.addElement('subscriptions')
280 e = stanza.addElement('error')
282 e.addElement((NS_XMPP_STANZAS, 'feature-not-implemented'))
283 uc = e.addElement(('http://jabber.org/protocol/pubsub#errors',
285 uc['feature'] = 'retrieve-subscriptions'
287 result = error.exceptionFromStanza(stanza)
288 self.assert_(isinstance(result, error.StanzaError))
289 self.assertEqual('feature-not-implemented', result.condition)
290 self.assertEqual('cancel', result.type)
291 self.assertEqual(uc, result.appCondition)
292 self.assertEqual([p], result.children)
294 def test_legacy(self):
296 Test legacy operations of exceptionFromStanza.
298 Given a realistic stanza with only legacy (pre-XMPP) error information,
299 check if a sane exception is returned.
303 <message type='error'
304 to='piers@pipetree.com/Home'
305 from='qmacro@jaber.org'>
306 <body>Are you there?</body>
307 <error code='502'>Unable to resolve hostname.</error>
310 stanza = domish.Element((None, 'stanza'))
311 p = stanza.addElement('body', content='Are you there?')
312 e = stanza.addElement('error', content='Unable to resolve hostname.')
315 result = error.exceptionFromStanza(stanza)
316 self.assert_(isinstance(result, error.StanzaError))
317 self.assertEqual('service-unavailable', result.condition)
318 self.assertEqual('wait', result.type)
319 self.assertEqual('Unable to resolve hostname.', result.text)
320 self.assertEqual([p], result.children)
322 class ExceptionFromStreamErrorTest(unittest.TestCase):
324 def test_basic(self):
326 Test basic operations of exceptionFromStreamError.
328 Given a realistic stream error, check if a sane exception is returned.
332 <stream:error xmlns:stream='http://etherx.jabber.org/streams'>
333 <xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
337 e = domish.Element(('http://etherx.jabber.org/streams', 'error'))
338 e.addElement((NS_XMPP_STREAMS, 'xml-not-well-formed'))
340 result = error.exceptionFromStreamError(e)
341 self.assert_(isinstance(result, error.StreamError))
342 self.assertEqual('xml-not-well-formed', result.condition)