test_patch_dispatch.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. from __future__ import unicode_literals
  2. from rest_framework.exceptions import ValidationError as ApiValidationError
  3. from django.core.exceptions import PermissionDenied, ValidationError
  4. from django.http import Http404
  5. from django.test import TestCase
  6. from misago.api.patch import ApiPatch
  7. class MockRequest(object):
  8. def __init__(self, data=None):
  9. self.data = data
  10. class MockObject(object):
  11. def __init__(self, pk):
  12. self.id = pk
  13. self.pk = pk
  14. class ApiPatchDispatchTests(TestCase):
  15. def test_dispatch(self):
  16. """dispatch calls actions and returns response"""
  17. patch = ApiPatch()
  18. def action_error(request, target, value):
  19. if value == '404':
  20. raise Http404()
  21. if value == '404_reason':
  22. raise Http404("something was removed")
  23. if value == 'perm':
  24. raise PermissionDenied("yo ain't doing that!")
  25. if value == 'invalid':
  26. raise ValidationError("invalid data here!")
  27. if value == 'api_invalid':
  28. raise ApiValidationError("invalid api data here!")
  29. patch.replace('error', action_error)
  30. def action_mutate(request, target, value):
  31. return {'value': value * 2}
  32. patch.replace('mutate', action_mutate)
  33. # dispatch requires list as an argument
  34. response = patch.dispatch(MockRequest({}), MockObject(13))
  35. self.assertEqual(response.status_code, 400)
  36. self.assertEqual(response.data, {
  37. 'non_field_errors': ["PATCH request should be a list of operations."],
  38. })
  39. # valid dispatch
  40. response = patch.dispatch(
  41. MockRequest([
  42. {
  43. 'op': 'replace',
  44. 'path': 'mutate',
  45. 'value': 6,
  46. },
  47. ]), MockObject(13)
  48. )
  49. self.assertEqual(response.status_code, 200)
  50. self.assertEqual(response.data, {'value': 12, 'id': 13})
  51. # invalid action in dispatch
  52. response = patch.dispatch(
  53. MockRequest([
  54. {
  55. 'op': 'replace',
  56. 'path': 'mutate',
  57. 'value': 6,
  58. },
  59. {
  60. 'op': 'replace',
  61. },
  62. ]), MockObject(13)
  63. )
  64. self.assertEqual(response.status_code, 400)
  65. self.assertEqual(response.data, {
  66. 'non_field_errors': ['"replace" op has to specify path.'],
  67. })
  68. # repeated action in dispatch
  69. response = patch.dispatch(
  70. MockRequest([
  71. {
  72. 'op': 'replace',
  73. 'path': 'mutate',
  74. 'value': 6,
  75. },
  76. {
  77. 'op': 'replace',
  78. 'path': 'mutate',
  79. 'value': 12,
  80. },
  81. ]), MockObject(13)
  82. )
  83. self.assertEqual(response.status_code, 400)
  84. self.assertEqual(response.data, {
  85. 'non_field_errors': ['"replace" op for "mutate" path is repeated.'],
  86. })
  87. # op raised validation error
  88. response = patch.dispatch(
  89. MockRequest([
  90. {
  91. 'op': 'replace',
  92. 'path': 'mutate',
  93. 'value': 6,
  94. },
  95. {
  96. 'op': 'replace',
  97. 'path': 'error',
  98. 'value': 'invalid',
  99. },
  100. ]), MockObject(13)
  101. )
  102. self.assertEqual(response.status_code, 400)
  103. self.assertEqual(response.data, {'value': ["invalid data here!"]})
  104. # op raised api validation error
  105. response = patch.dispatch(
  106. MockRequest([
  107. {
  108. 'op': 'replace',
  109. 'path': 'mutate',
  110. 'value': 6,
  111. },
  112. {
  113. 'op': 'replace',
  114. 'path': 'error',
  115. 'value': 'api_invalid',
  116. },
  117. ]), MockObject(13)
  118. )
  119. self.assertEqual(response.status_code, 400)
  120. self.assertEqual(response.data, {'value': ["invalid api data here!"]})
  121. # action in dispatch raised perm denied
  122. response = patch.dispatch(
  123. MockRequest([
  124. {
  125. 'op': 'replace',
  126. 'path': 'mutate',
  127. 'value': 6,
  128. },
  129. {
  130. 'op': 'replace',
  131. 'path': 'error',
  132. 'value': 'perm',
  133. },
  134. ]), MockObject(13)
  135. )
  136. self.assertEqual(response.status_code, 403)
  137. self.assertEqual(response.data, {'detail': "yo ain't doing that!"})
  138. # action in dispatch raised 404
  139. response = patch.dispatch(
  140. MockRequest([
  141. {
  142. 'op': 'replace',
  143. 'path': 'mutate',
  144. 'value': 6,
  145. },
  146. {
  147. 'op': 'replace',
  148. 'path': 'error',
  149. 'value': '404',
  150. },
  151. ]), MockObject(13)
  152. )
  153. self.assertEqual(response.status_code, 404)
  154. self.assertEqual(response.data, {'detail': 'NOT FOUND'})
  155. # action in dispatch raised 404 with message but didn't expose it
  156. response = patch.dispatch(
  157. MockRequest([
  158. {
  159. 'op': 'replace',
  160. 'path': 'mutate',
  161. 'value': 2,
  162. },
  163. {
  164. 'op': 'replace',
  165. 'path': 'error',
  166. 'value': '404_reason',
  167. },
  168. ]), MockObject(13)
  169. )
  170. self.assertEqual(response.status_code, 404)
  171. self.assertEqual(response.data, {'detail': 'NOT FOUND'})