summaryrefslogtreecommitdiff
path: root/tests/middleware_exceptions
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2020-02-12 15:15:00 -0700
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-03-18 19:59:12 +0100
commitfc0fa72ff4cdbf5861a366e31cb8bbacd44da22d (patch)
treed419ce531586808b0a111664907b859cb6d22862 /tests/middleware_exceptions
parent3f7e4b16bf58f99c71570ba75dc97db8265071be (diff)
Fixed #31224 -- Added support for asynchronous views and middleware.
This implements support for asynchronous views, asynchronous tests, asynchronous middleware, and an asynchronous test client.
Diffstat (limited to 'tests/middleware_exceptions')
-rw-r--r--tests/middleware_exceptions/middleware.py64
-rw-r--r--tests/middleware_exceptions/tests.py159
-rw-r--r--tests/middleware_exceptions/urls.py5
-rw-r--r--tests/middleware_exceptions/views.py8
4 files changed, 236 insertions, 0 deletions
diff --git a/tests/middleware_exceptions/middleware.py b/tests/middleware_exceptions/middleware.py
index 63502c6902..69c6db57e7 100644
--- a/tests/middleware_exceptions/middleware.py
+++ b/tests/middleware_exceptions/middleware.py
@@ -1,6 +1,9 @@
from django.http import Http404, HttpResponse
from django.template import engines
from django.template.response import TemplateResponse
+from django.utils.decorators import (
+ async_only_middleware, sync_and_async_middleware, sync_only_middleware,
+)
log = []
@@ -18,6 +21,12 @@ class ProcessExceptionMiddleware(BaseMiddleware):
return HttpResponse('Exception caught')
+@async_only_middleware
+class AsyncProcessExceptionMiddleware(BaseMiddleware):
+ async def process_exception(self, request, exception):
+ return HttpResponse('Exception caught')
+
+
class ProcessExceptionLogMiddleware(BaseMiddleware):
def process_exception(self, request, exception):
log.append('process-exception')
@@ -33,6 +42,12 @@ class ProcessViewMiddleware(BaseMiddleware):
return HttpResponse('Processed view %s' % view_func.__name__)
+@async_only_middleware
+class AsyncProcessViewMiddleware(BaseMiddleware):
+ async def process_view(self, request, view_func, view_args, view_kwargs):
+ return HttpResponse('Processed view %s' % view_func.__name__)
+
+
class ProcessViewNoneMiddleware(BaseMiddleware):
def process_view(self, request, view_func, view_args, view_kwargs):
log.append('processed view %s' % view_func.__name__)
@@ -51,6 +66,13 @@ class TemplateResponseMiddleware(BaseMiddleware):
return response
+@async_only_middleware
+class AsyncTemplateResponseMiddleware(BaseMiddleware):
+ async def process_template_response(self, request, response):
+ response.context_data['mw'].append(self.__class__.__name__)
+ return response
+
+
class LogMiddleware(BaseMiddleware):
def __call__(self, request):
response = self.get_response(request)
@@ -63,6 +85,48 @@ class NoTemplateResponseMiddleware(BaseMiddleware):
return None
+@async_only_middleware
+class AsyncNoTemplateResponseMiddleware(BaseMiddleware):
+ async def process_template_response(self, request, response):
+ return None
+
+
class NotFoundMiddleware(BaseMiddleware):
def __call__(self, request):
raise Http404('not found')
+
+
+class TeapotMiddleware(BaseMiddleware):
+ def __call__(self, request):
+ response = self.get_response(request)
+ response.status_code = 418
+ return response
+
+
+@async_only_middleware
+def async_teapot_middleware(get_response):
+ async def middleware(request):
+ response = await get_response(request)
+ response.status_code = 418
+ return response
+
+ return middleware
+
+
+@sync_and_async_middleware
+class SyncAndAsyncMiddleware(BaseMiddleware):
+ pass
+
+
+@sync_only_middleware
+class DecoratedTeapotMiddleware(TeapotMiddleware):
+ pass
+
+
+class NotSyncOrAsyncMiddleware(BaseMiddleware):
+ """Middleware that is deliberately neither sync or async."""
+ sync_capable = False
+ async_capable = False
+
+ def __call__(self, request):
+ return self.get_response(request)
diff --git a/tests/middleware_exceptions/tests.py b/tests/middleware_exceptions/tests.py
index 3e614ae0de..697841a35d 100644
--- a/tests/middleware_exceptions/tests.py
+++ b/tests/middleware_exceptions/tests.py
@@ -180,3 +180,162 @@ class MiddlewareNotUsedTests(SimpleTestCase):
with self.assertRaisesMessage(AssertionError, 'no logs'):
with self.assertLogs('django.request', 'DEBUG'):
self.client.get('/middleware_exceptions/view/')
+
+
+@override_settings(
+ DEBUG=True,
+ ROOT_URLCONF='middleware_exceptions.urls',
+)
+class MiddlewareSyncAsyncTests(SimpleTestCase):
+ @override_settings(MIDDLEWARE=[
+ 'middleware_exceptions.middleware.TeapotMiddleware',
+ ])
+ def test_sync_teapot_middleware(self):
+ response = self.client.get('/middleware_exceptions/view/')
+ self.assertEqual(response.status_code, 418)
+
+ @override_settings(MIDDLEWARE=[
+ 'middleware_exceptions.middleware.DecoratedTeapotMiddleware',
+ ])
+ def test_sync_decorated_teapot_middleware(self):
+ response = self.client.get('/middleware_exceptions/view/')
+ self.assertEqual(response.status_code, 418)
+
+ @override_settings(MIDDLEWARE=[
+ 'middleware_exceptions.middleware.async_teapot_middleware',
+ ])
+ def test_async_teapot_middleware(self):
+ with self.assertLogs('django.request', 'DEBUG') as cm:
+ response = self.client.get('/middleware_exceptions/view/')
+ self.assertEqual(response.status_code, 418)
+ self.assertEqual(
+ cm.records[0].getMessage(),
+ "Synchronous middleware "
+ "middleware_exceptions.middleware.async_teapot_middleware "
+ "adapted.",
+ )
+
+ @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.TeapotMiddleware',
+ ])
+ async def test_sync_teapot_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, 418)
+ self.assertEqual(
+ cm.records[0].getMessage(),
+ "Asynchronous middleware "
+ "middleware_exceptions.middleware.TeapotMiddleware adapted.",
+ )
+
+ @override_settings(MIDDLEWARE=[
+ 'middleware_exceptions.middleware.async_teapot_middleware',
+ ])
+ async def test_async_teapot_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, 418)
+ self.assertEqual(
+ cm.records[0].getMessage(),
+ 'Unknown Status Code: /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')
diff --git a/tests/middleware_exceptions/urls.py b/tests/middleware_exceptions/urls.py
index 46332916b6..d676ef470c 100644
--- a/tests/middleware_exceptions/urls.py
+++ b/tests/middleware_exceptions/urls.py
@@ -8,4 +8,9 @@ urlpatterns = [
path('middleware_exceptions/permission_denied/', views.permission_denied),
path('middleware_exceptions/exception_in_render/', views.exception_in_render),
path('middleware_exceptions/template_response/', views.template_response),
+ # Async views.
+ path(
+ 'middleware_exceptions/async_exception_in_render/',
+ views.async_exception_in_render,
+ ),
]
diff --git a/tests/middleware_exceptions/views.py b/tests/middleware_exceptions/views.py
index 3ae54081ab..7a1d244863 100644
--- a/tests/middleware_exceptions/views.py
+++ b/tests/middleware_exceptions/views.py
@@ -27,3 +27,11 @@ def exception_in_render(request):
raise Exception('Exception in HttpResponse.render()')
return CustomHttpResponse('Error')
+
+
+async def async_exception_in_render(request):
+ class CustomHttpResponse(HttpResponse):
+ async def render(self):
+ raise Exception('Exception in HttpResponse.render()')
+
+ return CustomHttpResponse('Error')