from django.conf import settings from django.core.exceptions import MiddlewareNotUsed from django.http import HttpResponse from django.test import RequestFactory, SimpleTestCase, override_settings from . import middleware as mw @override_settings(ROOT_URLCONF="middleware_exceptions.urls") class MiddlewareTests(SimpleTestCase): def tearDown(self): mw.log = [] @override_settings( MIDDLEWARE=["middleware_exceptions.middleware.ProcessViewNoneMiddleware"] ) def test_process_view_return_none(self): response = self.client.get("/middleware_exceptions/view/") self.assertEqual(mw.log, ["processed view normal_view"]) self.assertEqual(response.content, b"OK") @override_settings( MIDDLEWARE=["middleware_exceptions.middleware.ProcessViewMiddleware"] ) def test_process_view_return_response(self): response = self.client.get("/middleware_exceptions/view/") self.assertEqual(response.content, b"Processed view normal_view") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.ProcessViewTemplateResponseMiddleware", "middleware_exceptions.middleware.LogMiddleware", ] ) def test_templateresponse_from_process_view_rendered(self): """ TemplateResponses returned from process_view() must be rendered before being passed to any middleware that tries to access response.content, such as middleware_exceptions.middleware.LogMiddleware. """ response = self.client.get("/middleware_exceptions/view/") self.assertEqual( response.content, b"Processed view normal_view\nProcessViewTemplateResponseMiddleware", ) @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.ProcessViewTemplateResponseMiddleware", "middleware_exceptions.middleware.TemplateResponseMiddleware", ] ) def test_templateresponse_from_process_view_passed_to_process_template_response( self, ): """ TemplateResponses returned from process_view() should be passed to any template response middleware. """ response = self.client.get("/middleware_exceptions/view/") expected_lines = [ b"Processed view normal_view", b"ProcessViewTemplateResponseMiddleware", b"TemplateResponseMiddleware", ] self.assertEqual(response.content, b"\n".join(expected_lines)) @override_settings( MIDDLEWARE=["middleware_exceptions.middleware.TemplateResponseMiddleware"] ) def test_process_template_response(self): response = self.client.get("/middleware_exceptions/template_response/") self.assertEqual( response.content, b"template_response OK\nTemplateResponseMiddleware" ) @override_settings( MIDDLEWARE=["middleware_exceptions.middleware.NoTemplateResponseMiddleware"] ) def test_process_template_response_returns_none(self): msg = ( "NoTemplateResponseMiddleware.process_template_response didn't " "return an HttpResponse object. It returned None instead." ) with self.assertRaisesMessage(ValueError, msg): self.client.get("/middleware_exceptions/template_response/") @override_settings(MIDDLEWARE=["middleware_exceptions.middleware.LogMiddleware"]) def test_view_exception_converted_before_middleware(self): response = self.client.get("/middleware_exceptions/permission_denied/") self.assertEqual(mw.log, [(response.status_code, response.content)]) self.assertEqual(response.status_code, 403) @override_settings( MIDDLEWARE=["middleware_exceptions.middleware.ProcessExceptionMiddleware"] ) def test_view_exception_handled_by_process_exception(self): response = self.client.get("/middleware_exceptions/error/") self.assertEqual(response.content, b"Exception caught") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.ProcessExceptionLogMiddleware", "middleware_exceptions.middleware.ProcessExceptionMiddleware", ] ) def test_response_from_process_exception_short_circuits_remainder(self): response = self.client.get("/middleware_exceptions/error/") self.assertEqual(mw.log, []) self.assertEqual(response.content, b"Exception caught") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.ProcessExceptionMiddleware", "middleware_exceptions.middleware.ProcessExceptionLogMiddleware", ] ) def test_response_from_process_exception_when_return_response(self): response = self.client.get("/middleware_exceptions/error/") self.assertEqual(mw.log, ["process-exception"]) self.assertEqual(response.content, b"Exception caught") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.LogMiddleware", "middleware_exceptions.middleware.NotFoundMiddleware", ] ) def test_exception_in_middleware_converted_before_prior_middleware(self): response = self.client.get("/middleware_exceptions/view/") self.assertEqual(mw.log, [(404, response.content)]) self.assertEqual(response.status_code, 404) @override_settings( MIDDLEWARE=["middleware_exceptions.middleware.ProcessExceptionMiddleware"] ) def test_exception_in_render_passed_to_process_exception(self): response = self.client.get("/middleware_exceptions/exception_in_render/") self.assertEqual(response.content, b"Exception caught") @override_settings(ROOT_URLCONF="middleware_exceptions.urls") class RootUrlconfTests(SimpleTestCase): @override_settings(ROOT_URLCONF=None) def test_missing_root_urlconf(self): # Removing ROOT_URLCONF is safe, as override_settings will restore # the previously defined settings. del settings.ROOT_URLCONF with self.assertRaises(AttributeError): self.client.get("/middleware_exceptions/view/") class MyMiddleware: def __init__(self, get_response): raise MiddlewareNotUsed def process_request(self, request): pass class MyMiddlewareWithExceptionMessage: def __init__(self, get_response): raise MiddlewareNotUsed("spam eggs") def process_request(self, request): pass @override_settings( DEBUG=True, ROOT_URLCONF="middleware_exceptions.urls", MIDDLEWARE=["django.middleware.common.CommonMiddleware"], ) class MiddlewareNotUsedTests(SimpleTestCase): rf = RequestFactory() def test_raise_exception(self): request = self.rf.get("middleware_exceptions/view/") with self.assertRaises(MiddlewareNotUsed): MyMiddleware(lambda req: HttpResponse()).process_request(request) @override_settings(MIDDLEWARE=["middleware_exceptions.tests.MyMiddleware"]) def test_log(self): with self.assertLogs("django.request", "DEBUG") as cm: self.client.get("/middleware_exceptions/view/") self.assertEqual( cm.records[0].getMessage(), "MiddlewareNotUsed: 'middleware_exceptions.tests.MyMiddleware'", ) @override_settings( MIDDLEWARE=["middleware_exceptions.tests.MyMiddlewareWithExceptionMessage"] ) def test_log_custom_message(self): with self.assertLogs("django.request", "DEBUG") as cm: self.client.get("/middleware_exceptions/view/") self.assertEqual( cm.records[0].getMessage(), "MiddlewareNotUsed('middleware_exceptions.tests." "MyMiddlewareWithExceptionMessage'): spam eggs", ) @override_settings( DEBUG=False, MIDDLEWARE=["middleware_exceptions.tests.MyMiddleware"], ) def test_do_not_log_when_debug_is_false(self): with self.assertNoLogs("django.request", "DEBUG"): self.client.get("/middleware_exceptions/view/") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.SyncAndAsyncMiddleware", "middleware_exceptions.tests.MyMiddleware", ] ) async def test_async_and_sync_middleware_chain_async_call(self): with self.assertLogs("django.request", "DEBUG") as cm: response = await self.async_client.get("/middleware_exceptions/view/") self.assertEqual(response.content, b"OK") self.assertEqual(response.status_code, 200) self.assertEqual( cm.records[0].getMessage(), "Asynchronous handler adapted for middleware " "middleware_exceptions.tests.MyMiddleware.", ) self.assertEqual( cm.records[1].getMessage(), "MiddlewareNotUsed: 'middleware_exceptions.tests.MyMiddleware'", ) @override_settings( DEBUG=True, ROOT_URLCONF="middleware_exceptions.urls", ) class MiddlewareSyncAsyncTests(SimpleTestCase): @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.PaymentMiddleware", ] ) def test_sync_middleware(self): response = self.client.get("/middleware_exceptions/view/") self.assertEqual(response.status_code, 402) @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.DecoratedPaymentMiddleware", ] ) def test_sync_decorated_middleware(self): response = self.client.get("/middleware_exceptions/view/") self.assertEqual(response.status_code, 402) @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.async_payment_middleware", ] ) def test_async_middleware(self): with self.assertLogs("django.request", "DEBUG") as cm: response = self.client.get("/middleware_exceptions/view/") self.assertEqual(response.status_code, 402) self.assertEqual( cm.records[0].getMessage(), "Synchronous handler adapted for middleware " "middleware_exceptions.middleware.async_payment_middleware.", ) @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.NotSyncOrAsyncMiddleware", ] ) def test_not_sync_or_async_middleware(self): msg = ( "Middleware " "middleware_exceptions.middleware.NotSyncOrAsyncMiddleware must " "have at least one of sync_capable/async_capable set to True." ) with self.assertRaisesMessage(RuntimeError, msg): self.client.get("/middleware_exceptions/view/") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.PaymentMiddleware", ] ) async def test_sync_middleware_async(self): with self.assertLogs("django.request", "DEBUG") as cm: response = await self.async_client.get("/middleware_exceptions/view/") self.assertEqual(response.status_code, 402) self.assertEqual( cm.records[0].getMessage(), "Asynchronous handler adapted for middleware " "middleware_exceptions.middleware.PaymentMiddleware.", ) @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.async_payment_middleware", ] ) async def test_async_middleware_async(self): with self.assertLogs("django.request", "WARNING") as cm: response = await self.async_client.get("/middleware_exceptions/view/") self.assertEqual(response.status_code, 402) self.assertEqual( cm.records[0].getMessage(), "Payment Required: /middleware_exceptions/view/", ) @override_settings( DEBUG=False, MIDDLEWARE=[ "middleware_exceptions.middleware.AsyncNoTemplateResponseMiddleware", ], ) def test_async_process_template_response_returns_none_with_sync_client(self): msg = ( "AsyncNoTemplateResponseMiddleware.process_template_response " "didn't return an HttpResponse object." ) with self.assertRaisesMessage(ValueError, msg): self.client.get("/middleware_exceptions/template_response/") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.SyncAndAsyncMiddleware", ] ) async def test_async_and_sync_middleware_async_call(self): response = await self.async_client.get("/middleware_exceptions/view/") self.assertEqual(response.content, b"OK") self.assertEqual(response.status_code, 200) @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.SyncAndAsyncMiddleware", ] ) def test_async_and_sync_middleware_sync_call(self): response = self.client.get("/middleware_exceptions/view/") self.assertEqual(response.content, b"OK") self.assertEqual(response.status_code, 200) @override_settings(ROOT_URLCONF="middleware_exceptions.urls") class AsyncMiddlewareTests(SimpleTestCase): @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.AsyncTemplateResponseMiddleware", ] ) async def test_process_template_response(self): response = await self.async_client.get( "/middleware_exceptions/template_response/" ) self.assertEqual( response.content, b"template_response OK\nAsyncTemplateResponseMiddleware", ) @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.AsyncNoTemplateResponseMiddleware", ] ) async def test_process_template_response_returns_none(self): msg = ( "AsyncNoTemplateResponseMiddleware.process_template_response " "didn't return an HttpResponse object. It returned None instead." ) with self.assertRaisesMessage(ValueError, msg): await self.async_client.get("/middleware_exceptions/template_response/") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.AsyncProcessExceptionMiddleware", ] ) async def test_exception_in_render_passed_to_process_exception(self): response = await self.async_client.get( "/middleware_exceptions/exception_in_render/" ) self.assertEqual(response.content, b"Exception caught") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.AsyncProcessExceptionMiddleware", ] ) async def test_exception_in_async_render_passed_to_process_exception(self): response = await self.async_client.get( "/middleware_exceptions/async_exception_in_render/" ) self.assertEqual(response.content, b"Exception caught") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.AsyncProcessExceptionMiddleware", ] ) async def test_view_exception_handled_by_process_exception(self): response = await self.async_client.get("/middleware_exceptions/error/") self.assertEqual(response.content, b"Exception caught") @override_settings( MIDDLEWARE=[ "middleware_exceptions.middleware.AsyncProcessViewMiddleware", ] ) async def test_process_view_return_response(self): response = await self.async_client.get("/middleware_exceptions/view/") self.assertEqual(response.content, b"Processed view normal_view")