tests.py 15 KB

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