test_jabbererror.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.words.protocols.jabber.error}.
  5. """
  6. from __future__ import absolute_import, division
  7. from twisted.python.compat import unicode
  8. from twisted.trial import unittest
  9. from twisted.words.protocols.jabber import error
  10. from twisted.words.xish import domish
  11. NS_XML = 'http://www.w3.org/XML/1998/namespace'
  12. NS_STREAMS = 'http://etherx.jabber.org/streams'
  13. NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams'
  14. NS_XMPP_STANZAS = 'urn:ietf:params:xml:ns:xmpp-stanzas'
  15. class BaseErrorTests(unittest.TestCase):
  16. def test_getElementPlain(self):
  17. """
  18. Test getting an element for a plain error.
  19. """
  20. e = error.BaseError('feature-not-implemented')
  21. element = e.getElement()
  22. self.assertIdentical(element.uri, None)
  23. self.assertEqual(len(element.children), 1)
  24. def test_getElementText(self):
  25. """
  26. Test getting an element for an error with a text.
  27. """
  28. e = error.BaseError('feature-not-implemented', u'text')
  29. element = e.getElement()
  30. self.assertEqual(len(element.children), 2)
  31. self.assertEqual(unicode(element.text), 'text')
  32. self.assertEqual(element.text.getAttribute((NS_XML, 'lang')), None)
  33. def test_getElementTextLang(self):
  34. """
  35. Test getting an element for an error with a text and language.
  36. """
  37. e = error.BaseError('feature-not-implemented', u'text', 'en_US')
  38. element = e.getElement()
  39. self.assertEqual(len(element.children), 2)
  40. self.assertEqual(unicode(element.text), 'text')
  41. self.assertEqual(element.text[(NS_XML, 'lang')], 'en_US')
  42. def test_getElementAppCondition(self):
  43. """
  44. Test getting an element for an error with an app specific condition.
  45. """
  46. ac = domish.Element(('testns', 'myerror'))
  47. e = error.BaseError('feature-not-implemented', appCondition=ac)
  48. element = e.getElement()
  49. self.assertEqual(len(element.children), 2)
  50. self.assertEqual(element.myerror, ac)
  51. class StreamErrorTests(unittest.TestCase):
  52. def test_getElementPlain(self):
  53. """
  54. Test namespace of the element representation of an error.
  55. """
  56. e = error.StreamError('feature-not-implemented')
  57. element = e.getElement()
  58. self.assertEqual(element.uri, NS_STREAMS)
  59. def test_getElementConditionNamespace(self):
  60. """
  61. Test that the error condition element has the correct namespace.
  62. """
  63. e = error.StreamError('feature-not-implemented')
  64. element = e.getElement()
  65. self.assertEqual(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri)
  66. def test_getElementTextNamespace(self):
  67. """
  68. Test that the error text element has the correct namespace.
  69. """
  70. e = error.StreamError('feature-not-implemented', u'text')
  71. element = e.getElement()
  72. self.assertEqual(NS_XMPP_STREAMS, element.text.uri)
  73. class StanzaErrorTests(unittest.TestCase):
  74. """
  75. Tests for L{error.StreamError}.
  76. """
  77. def test_typeRemoteServerTimeout(self):
  78. """
  79. Remote Server Timeout should yield type wait, code 504.
  80. """
  81. e = error.StanzaError('remote-server-timeout')
  82. self.assertEqual('wait', e.type)
  83. self.assertEqual('504', e.code)
  84. def test_getElementPlain(self):
  85. """
  86. Test getting an element for a plain stanza error.
  87. """
  88. e = error.StanzaError('feature-not-implemented')
  89. element = e.getElement()
  90. self.assertEqual(element.uri, None)
  91. self.assertEqual(element['type'], 'cancel')
  92. self.assertEqual(element['code'], '501')
  93. def test_getElementType(self):
  94. """
  95. Test getting an element for a stanza error with a given type.
  96. """
  97. e = error.StanzaError('feature-not-implemented', 'auth')
  98. element = e.getElement()
  99. self.assertEqual(element.uri, None)
  100. self.assertEqual(element['type'], 'auth')
  101. self.assertEqual(element['code'], '501')
  102. def test_getElementConditionNamespace(self):
  103. """
  104. Test that the error condition element has the correct namespace.
  105. """
  106. e = error.StanzaError('feature-not-implemented')
  107. element = e.getElement()
  108. self.assertEqual(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri)
  109. def test_getElementTextNamespace(self):
  110. """
  111. Test that the error text element has the correct namespace.
  112. """
  113. e = error.StanzaError('feature-not-implemented', text=u'text')
  114. element = e.getElement()
  115. self.assertEqual(NS_XMPP_STANZAS, element.text.uri)
  116. def test_toResponse(self):
  117. """
  118. Test an error response is generated from a stanza.
  119. The addressing on the (new) response stanza should be reversed, an
  120. error child (with proper properties) added and the type set to
  121. C{'error'}.
  122. """
  123. stanza = domish.Element(('jabber:client', 'message'))
  124. stanza['type'] = 'chat'
  125. stanza['to'] = 'user1@example.com'
  126. stanza['from'] = 'user2@example.com/resource'
  127. e = error.StanzaError('service-unavailable')
  128. response = e.toResponse(stanza)
  129. self.assertNotIdentical(response, stanza)
  130. self.assertEqual(response['from'], 'user1@example.com')
  131. self.assertEqual(response['to'], 'user2@example.com/resource')
  132. self.assertEqual(response['type'], 'error')
  133. self.assertEqual(response.error.children[0].name,
  134. 'service-unavailable')
  135. self.assertEqual(response.error['type'], 'cancel')
  136. self.assertNotEqual(stanza.children, response.children)
  137. class ParseErrorTests(unittest.TestCase):
  138. """
  139. Tests for L{error._parseError}.
  140. """
  141. def setUp(self):
  142. self.error = domish.Element((None, 'error'))
  143. def test_empty(self):
  144. """
  145. Test parsing of the empty error element.
  146. """
  147. result = error._parseError(self.error, 'errorns')
  148. self.assertEqual({'condition': None,
  149. 'text': None,
  150. 'textLang': None,
  151. 'appCondition': None}, result)
  152. def test_condition(self):
  153. """
  154. Test parsing of an error element with a condition.
  155. """
  156. self.error.addElement(('errorns', 'bad-request'))
  157. result = error._parseError(self.error, 'errorns')
  158. self.assertEqual('bad-request', result['condition'])
  159. def test_text(self):
  160. """
  161. Test parsing of an error element with a text.
  162. """
  163. text = self.error.addElement(('errorns', 'text'))
  164. text.addContent(u'test')
  165. result = error._parseError(self.error, 'errorns')
  166. self.assertEqual('test', result['text'])
  167. self.assertEqual(None, result['textLang'])
  168. def test_textLang(self):
  169. """
  170. Test parsing of an error element with a text with a defined language.
  171. """
  172. text = self.error.addElement(('errorns', 'text'))
  173. text[NS_XML, 'lang'] = 'en_US'
  174. text.addContent(u'test')
  175. result = error._parseError(self.error, 'errorns')
  176. self.assertEqual('en_US', result['textLang'])
  177. def test_appCondition(self):
  178. """
  179. Test parsing of an error element with an app specific condition.
  180. """
  181. condition = self.error.addElement(('testns', 'condition'))
  182. result = error._parseError(self.error, 'errorns')
  183. self.assertEqual(condition, result['appCondition'])
  184. def test_appConditionMultiple(self):
  185. """
  186. Test parsing of an error element with multiple app specific conditions.
  187. """
  188. self.error.addElement(('testns', 'condition'))
  189. condition = self.error.addElement(('testns', 'condition2'))
  190. result = error._parseError(self.error, 'errorns')
  191. self.assertEqual(condition, result['appCondition'])
  192. class ExceptionFromStanzaTests(unittest.TestCase):
  193. def test_basic(self):
  194. """
  195. Test basic operations of exceptionFromStanza.
  196. Given a realistic stanza, check if a sane exception is returned.
  197. Using this stanza::
  198. <iq type='error'
  199. from='pubsub.shakespeare.lit'
  200. to='francisco@denmark.lit/barracks'
  201. id='subscriptions1'>
  202. <pubsub xmlns='http://jabber.org/protocol/pubsub'>
  203. <subscriptions/>
  204. </pubsub>
  205. <error type='cancel'>
  206. <feature-not-implemented
  207. xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
  208. <unsupported xmlns='http://jabber.org/protocol/pubsub#errors'
  209. feature='retrieve-subscriptions'/>
  210. </error>
  211. </iq>
  212. """
  213. stanza = domish.Element((None, 'stanza'))
  214. p = stanza.addElement(('http://jabber.org/protocol/pubsub', 'pubsub'))
  215. p.addElement('subscriptions')
  216. e = stanza.addElement('error')
  217. e['type'] = 'cancel'
  218. e.addElement((NS_XMPP_STANZAS, 'feature-not-implemented'))
  219. uc = e.addElement(('http://jabber.org/protocol/pubsub#errors',
  220. 'unsupported'))
  221. uc['feature'] = 'retrieve-subscriptions'
  222. result = error.exceptionFromStanza(stanza)
  223. self.assertIsInstance(result, error.StanzaError)
  224. self.assertEqual('feature-not-implemented', result.condition)
  225. self.assertEqual('cancel', result.type)
  226. self.assertEqual(uc, result.appCondition)
  227. self.assertEqual([p], result.children)
  228. def test_legacy(self):
  229. """
  230. Test legacy operations of exceptionFromStanza.
  231. Given a realistic stanza with only legacy (pre-XMPP) error information,
  232. check if a sane exception is returned.
  233. Using this stanza::
  234. <message type='error'
  235. to='piers@pipetree.com/Home'
  236. from='qmacro@jaber.org'>
  237. <body>Are you there?</body>
  238. <error code='502'>Unable to resolve hostname.</error>
  239. </message>
  240. """
  241. stanza = domish.Element((None, 'stanza'))
  242. p = stanza.addElement('body', content=u'Are you there?')
  243. e = stanza.addElement('error', content=u'Unable to resolve hostname.')
  244. e['code'] = '502'
  245. result = error.exceptionFromStanza(stanza)
  246. self.assertIsInstance(result, error.StanzaError)
  247. self.assertEqual('service-unavailable', result.condition)
  248. self.assertEqual('wait', result.type)
  249. self.assertEqual('Unable to resolve hostname.', result.text)
  250. self.assertEqual([p], result.children)
  251. class ExceptionFromStreamErrorTests(unittest.TestCase):
  252. def test_basic(self):
  253. """
  254. Test basic operations of exceptionFromStreamError.
  255. Given a realistic stream error, check if a sane exception is returned.
  256. Using this error::
  257. <stream:error xmlns:stream='http://etherx.jabber.org/streams'>
  258. <xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
  259. </stream:error>
  260. """
  261. e = domish.Element(('http://etherx.jabber.org/streams', 'error'))
  262. e.addElement((NS_XMPP_STREAMS, 'xml-not-well-formed'))
  263. result = error.exceptionFromStreamError(e)
  264. self.assertIsInstance(result, error.StreamError)
  265. self.assertEqual('xml-not-well-formed', result.condition)