tests.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. from django.conf import settings
  2. from django.core.exceptions import MiddlewareNotUsed
  3. from django.http import HttpResponse
  4. from django.test import RequestFactory, SimpleTestCase, override_settings
  5. from . import middleware as mw
  6. @override_settings(ROOT_URLCONF='middleware_exceptions.urls')
  7. class MiddlewareTests(SimpleTestCase):
  8. def tearDown(self):
  9. mw.log = []
  10. @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.ProcessViewNoneMiddleware'])
  11. def test_process_view_return_none(self):
  12. response = self.client.get('/middleware_exceptions/view/')
  13. self.assertEqual(mw.log, ['processed view normal_view'])
  14. self.assertEqual(response.content, b'OK')
  15. @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.ProcessViewMiddleware'])
  16. def test_process_view_return_response(self):
  17. response = self.client.get('/middleware_exceptions/view/')
  18. self.assertEqual(response.content, b'Processed view normal_view')
  19. @override_settings(MIDDLEWARE=[
  20. 'middleware_exceptions.middleware.ProcessViewTemplateResponseMiddleware',
  21. 'middleware_exceptions.middleware.LogMiddleware',
  22. ])
  23. def test_templateresponse_from_process_view_rendered(self):
  24. """
  25. TemplateResponses returned from process_view() must be rendered before
  26. being passed to any middleware that tries to access response.content,
  27. such as middleware_exceptions.middleware.LogMiddleware.
  28. """
  29. response = self.client.get('/middleware_exceptions/view/')
  30. self.assertEqual(response.content, b'Processed view normal_view\nProcessViewTemplateResponseMiddleware')
  31. @override_settings(MIDDLEWARE=[
  32. 'middleware_exceptions.middleware.ProcessViewTemplateResponseMiddleware',
  33. 'middleware_exceptions.middleware.TemplateResponseMiddleware',
  34. ])
  35. def test_templateresponse_from_process_view_passed_to_process_template_response(self):
  36. """
  37. TemplateResponses returned from process_view() should be passed to any
  38. template response middleware.
  39. """
  40. response = self.client.get('/middleware_exceptions/view/')
  41. expected_lines = [
  42. b'Processed view normal_view',
  43. b'ProcessViewTemplateResponseMiddleware',
  44. b'TemplateResponseMiddleware',
  45. ]
  46. self.assertEqual(response.content, b'\n'.join(expected_lines))
  47. @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.TemplateResponseMiddleware'])
  48. def test_process_template_response(self):
  49. response = self.client.get('/middleware_exceptions/template_response/')
  50. self.assertEqual(response.content, b'template_response OK\nTemplateResponseMiddleware')
  51. @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.NoTemplateResponseMiddleware'])
  52. def test_process_template_response_returns_none(self):
  53. msg = (
  54. "NoTemplateResponseMiddleware.process_template_response didn't "
  55. "return an HttpResponse object. It returned None instead."
  56. )
  57. with self.assertRaisesMessage(ValueError, msg):
  58. self.client.get('/middleware_exceptions/template_response/')
  59. @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.LogMiddleware'])
  60. def test_view_exception_converted_before_middleware(self):
  61. response = self.client.get('/middleware_exceptions/permission_denied/')
  62. self.assertEqual(mw.log, [(response.status_code, response.content)])
  63. self.assertEqual(response.status_code, 403)
  64. @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.ProcessExceptionMiddleware'])
  65. def test_view_exception_handled_by_process_exception(self):
  66. response = self.client.get('/middleware_exceptions/error/')
  67. self.assertEqual(response.content, b'Exception caught')
  68. @override_settings(MIDDLEWARE=[
  69. 'middleware_exceptions.middleware.ProcessExceptionLogMiddleware',
  70. 'middleware_exceptions.middleware.ProcessExceptionMiddleware',
  71. ])
  72. def test_response_from_process_exception_short_circuits_remainder(self):
  73. response = self.client.get('/middleware_exceptions/error/')
  74. self.assertEqual(mw.log, [])
  75. self.assertEqual(response.content, b'Exception caught')
  76. @override_settings(MIDDLEWARE=[
  77. 'middleware_exceptions.middleware.ProcessExceptionMiddleware',
  78. 'middleware_exceptions.middleware.ProcessExceptionLogMiddleware',
  79. ])
  80. def test_response_from_process_exception_when_return_response(self):
  81. response = self.client.get('/middleware_exceptions/error/')
  82. self.assertEqual(mw.log, ['process-exception'])
  83. self.assertEqual(response.content, b'Exception caught')
  84. @override_settings(MIDDLEWARE=[
  85. 'middleware_exceptions.middleware.LogMiddleware',
  86. 'middleware_exceptions.middleware.NotFoundMiddleware',
  87. ])
  88. def test_exception_in_middleware_converted_before_prior_middleware(self):
  89. response = self.client.get('/middleware_exceptions/view/')
  90. self.assertEqual(mw.log, [(404, response.content)])
  91. self.assertEqual(response.status_code, 404)
  92. @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.ProcessExceptionMiddleware'])
  93. def test_exception_in_render_passed_to_process_exception(self):
  94. response = self.client.get('/middleware_exceptions/exception_in_render/')
  95. self.assertEqual(response.content, b'Exception caught')
  96. @override_settings(ROOT_URLCONF='middleware_exceptions.urls')
  97. class RootUrlconfTests(SimpleTestCase):
  98. @override_settings(ROOT_URLCONF=None)
  99. def test_missing_root_urlconf(self):
  100. # Removing ROOT_URLCONF is safe, as override_settings will restore
  101. # the previously defined settings.
  102. del settings.ROOT_URLCONF
  103. with self.assertRaises(AttributeError):
  104. self.client.get("/middleware_exceptions/view/")
  105. class MyMiddleware:
  106. def __init__(self, get_response):
  107. raise MiddlewareNotUsed
  108. def process_request(self, request):
  109. pass
  110. class MyMiddlewareWithExceptionMessage:
  111. def __init__(self, get_response):
  112. raise MiddlewareNotUsed('spam eggs')
  113. def process_request(self, request):
  114. pass
  115. @override_settings(
  116. DEBUG=True,
  117. ROOT_URLCONF='middleware_exceptions.urls',
  118. MIDDLEWARE=['django.middleware.common.CommonMiddleware'],
  119. )
  120. class MiddlewareNotUsedTests(SimpleTestCase):
  121. rf = RequestFactory()
  122. def test_raise_exception(self):
  123. request = self.rf.get('middleware_exceptions/view/')
  124. with self.assertRaises(MiddlewareNotUsed):
  125. MyMiddleware(lambda req: HttpResponse()).process_request(request)
  126. @override_settings(MIDDLEWARE=['middleware_exceptions.tests.MyMiddleware'])
  127. def test_log(self):
  128. with self.assertLogs('django.request', 'DEBUG') as cm:
  129. self.client.get('/middleware_exceptions/view/')
  130. self.assertEqual(
  131. cm.records[0].getMessage(),
  132. "MiddlewareNotUsed: 'middleware_exceptions.tests.MyMiddleware'"
  133. )
  134. @override_settings(MIDDLEWARE=['middleware_exceptions.tests.MyMiddlewareWithExceptionMessage'])
  135. def test_log_custom_message(self):
  136. with self.assertLogs('django.request', 'DEBUG') as cm:
  137. self.client.get('/middleware_exceptions/view/')
  138. self.assertEqual(
  139. cm.records[0].getMessage(),
  140. "MiddlewareNotUsed('middleware_exceptions.tests.MyMiddlewareWithExceptionMessage'): spam eggs"
  141. )
  142. @override_settings(
  143. DEBUG=False,
  144. MIDDLEWARE=['middleware_exceptions.tests.MyMiddleware'],
  145. )
  146. def test_do_not_log_when_debug_is_false(self):
  147. with self.assertNoLogs('django.request', 'DEBUG'):
  148. self.client.get('/middleware_exceptions/view/')
  149. @override_settings(MIDDLEWARE=[
  150. 'middleware_exceptions.middleware.SyncAndAsyncMiddleware',
  151. 'middleware_exceptions.tests.MyMiddleware',
  152. ])
  153. async def test_async_and_sync_middleware_chain_async_call(self):
  154. with self.assertLogs('django.request', 'DEBUG') as cm:
  155. response = await self.async_client.get('/middleware_exceptions/view/')
  156. self.assertEqual(response.content, b'OK')
  157. self.assertEqual(response.status_code, 200)
  158. self.assertEqual(
  159. cm.records[0].getMessage(),
  160. 'Asynchronous middleware middleware_exceptions.tests.MyMiddleware '
  161. 'adapted.',
  162. )
  163. self.assertEqual(
  164. cm.records[1].getMessage(),
  165. "MiddlewareNotUsed: 'middleware_exceptions.tests.MyMiddleware'",
  166. )
  167. @override_settings(
  168. DEBUG=True,
  169. ROOT_URLCONF='middleware_exceptions.urls',
  170. )
  171. class MiddlewareSyncAsyncTests(SimpleTestCase):
  172. @override_settings(MIDDLEWARE=[
  173. 'middleware_exceptions.middleware.PaymentMiddleware',
  174. ])
  175. def test_sync_middleware(self):
  176. response = self.client.get('/middleware_exceptions/view/')
  177. self.assertEqual(response.status_code, 402)
  178. @override_settings(MIDDLEWARE=[
  179. 'middleware_exceptions.middleware.DecoratedPaymentMiddleware',
  180. ])
  181. def test_sync_decorated_middleware(self):
  182. response = self.client.get('/middleware_exceptions/view/')
  183. self.assertEqual(response.status_code, 402)
  184. @override_settings(MIDDLEWARE=[
  185. 'middleware_exceptions.middleware.async_payment_middleware',
  186. ])
  187. def test_async_middleware(self):
  188. with self.assertLogs('django.request', 'DEBUG') as cm:
  189. response = self.client.get('/middleware_exceptions/view/')
  190. self.assertEqual(response.status_code, 402)
  191. self.assertEqual(
  192. cm.records[0].getMessage(),
  193. "Synchronous middleware "
  194. "middleware_exceptions.middleware.async_payment_middleware "
  195. "adapted.",
  196. )
  197. @override_settings(MIDDLEWARE=[
  198. 'middleware_exceptions.middleware.NotSyncOrAsyncMiddleware',
  199. ])
  200. def test_not_sync_or_async_middleware(self):
  201. msg = (
  202. 'Middleware '
  203. 'middleware_exceptions.middleware.NotSyncOrAsyncMiddleware must '
  204. 'have at least one of sync_capable/async_capable set to True.'
  205. )
  206. with self.assertRaisesMessage(RuntimeError, msg):
  207. self.client.get('/middleware_exceptions/view/')
  208. @override_settings(MIDDLEWARE=[
  209. 'middleware_exceptions.middleware.PaymentMiddleware',
  210. ])
  211. async def test_sync_middleware_async(self):
  212. with self.assertLogs('django.request', 'DEBUG') as cm:
  213. response = await self.async_client.get('/middleware_exceptions/view/')
  214. self.assertEqual(response.status_code, 402)
  215. self.assertEqual(
  216. cm.records[0].getMessage(),
  217. "Asynchronous middleware "
  218. "middleware_exceptions.middleware.PaymentMiddleware adapted.",
  219. )
  220. @override_settings(MIDDLEWARE=[
  221. 'middleware_exceptions.middleware.async_payment_middleware',
  222. ])
  223. async def test_async_middleware_async(self):
  224. with self.assertLogs('django.request', 'WARNING') as cm:
  225. response = await self.async_client.get('/middleware_exceptions/view/')
  226. self.assertEqual(response.status_code, 402)
  227. self.assertEqual(
  228. cm.records[0].getMessage(),
  229. 'Payment Required: /middleware_exceptions/view/',
  230. )
  231. @override_settings(
  232. DEBUG=False,
  233. MIDDLEWARE=[
  234. 'middleware_exceptions.middleware.AsyncNoTemplateResponseMiddleware',
  235. ],
  236. )
  237. def test_async_process_template_response_returns_none_with_sync_client(self):
  238. msg = (
  239. "AsyncNoTemplateResponseMiddleware.process_template_response "
  240. "didn't return an HttpResponse object."
  241. )
  242. with self.assertRaisesMessage(ValueError, msg):
  243. self.client.get('/middleware_exceptions/template_response/')
  244. @override_settings(MIDDLEWARE=[
  245. 'middleware_exceptions.middleware.SyncAndAsyncMiddleware',
  246. ])
  247. async def test_async_and_sync_middleware_async_call(self):
  248. response = await self.async_client.get('/middleware_exceptions/view/')
  249. self.assertEqual(response.content, b'OK')
  250. self.assertEqual(response.status_code, 200)
  251. @override_settings(MIDDLEWARE=[
  252. 'middleware_exceptions.middleware.SyncAndAsyncMiddleware',
  253. ])
  254. def test_async_and_sync_middleware_sync_call(self):
  255. response = self.client.get('/middleware_exceptions/view/')
  256. self.assertEqual(response.content, b'OK')
  257. self.assertEqual(response.status_code, 200)
  258. @override_settings(ROOT_URLCONF='middleware_exceptions.urls')
  259. class AsyncMiddlewareTests(SimpleTestCase):
  260. @override_settings(MIDDLEWARE=[
  261. 'middleware_exceptions.middleware.AsyncTemplateResponseMiddleware',
  262. ])
  263. async def test_process_template_response(self):
  264. response = await self.async_client.get(
  265. '/middleware_exceptions/template_response/'
  266. )
  267. self.assertEqual(
  268. response.content,
  269. b'template_response OK\nAsyncTemplateResponseMiddleware',
  270. )
  271. @override_settings(MIDDLEWARE=[
  272. 'middleware_exceptions.middleware.AsyncNoTemplateResponseMiddleware',
  273. ])
  274. async def test_process_template_response_returns_none(self):
  275. msg = (
  276. "AsyncNoTemplateResponseMiddleware.process_template_response "
  277. "didn't return an HttpResponse object. It returned None instead."
  278. )
  279. with self.assertRaisesMessage(ValueError, msg):
  280. await self.async_client.get('/middleware_exceptions/template_response/')
  281. @override_settings(MIDDLEWARE=[
  282. 'middleware_exceptions.middleware.AsyncProcessExceptionMiddleware',
  283. ])
  284. async def test_exception_in_render_passed_to_process_exception(self):
  285. response = await self.async_client.get(
  286. '/middleware_exceptions/exception_in_render/'
  287. )
  288. self.assertEqual(response.content, b'Exception caught')
  289. @override_settings(MIDDLEWARE=[
  290. 'middleware_exceptions.middleware.AsyncProcessExceptionMiddleware',
  291. ])
  292. async def test_exception_in_async_render_passed_to_process_exception(self):
  293. response = await self.async_client.get(
  294. '/middleware_exceptions/async_exception_in_render/'
  295. )
  296. self.assertEqual(response.content, b'Exception caught')
  297. @override_settings(MIDDLEWARE=[
  298. 'middleware_exceptions.middleware.AsyncProcessExceptionMiddleware',
  299. ])
  300. async def test_view_exception_handled_by_process_exception(self):
  301. response = await self.async_client.get('/middleware_exceptions/error/')
  302. self.assertEqual(response.content, b'Exception caught')
  303. @override_settings(MIDDLEWARE=[
  304. 'middleware_exceptions.middleware.AsyncProcessViewMiddleware',
  305. ])
  306. async def test_process_view_return_response(self):
  307. response = await self.async_client.get('/middleware_exceptions/view/')
  308. self.assertEqual(response.content, b'Processed view normal_view')