summaryrefslogtreecommitdiff
path: root/tests/async
diff options
context:
space:
mode:
authorCarlton Gibson <carlton.gibson@noumenal.es>2022-04-07 07:05:59 +0200
committerGitHub <noreply@github.com>2022-04-07 07:05:59 +0200
commit9ffd4eae2ce7a7100c98f681e2b6ab818df384a4 (patch)
tree2cc678b6feff9f187517439bf2856a8702c1f356 /tests/async
parent2ee4caf56b8e000cabbb73ad81ff05738d6d0a35 (diff)
downloaddjango-9ffd4eae2ce7a7100c98f681e2b6ab818df384a4.tar.gz
Fixed #33611 -- Allowed View subclasses to define async method handlers.
Diffstat (limited to 'tests/async')
-rw-r--r--tests/async/tests.py68
1 files changed, 67 insertions, 1 deletions
diff --git a/tests/async/tests.py b/tests/async/tests.py
index be3e4e2576..1a0627a064 100644
--- a/tests/async/tests.py
+++ b/tests/async/tests.py
@@ -1,3 +1,4 @@
+import asyncio
import os
import sys
from unittest import mock, skipIf
@@ -5,9 +6,11 @@ from unittest import mock, skipIf
from asgiref.sync import async_to_sync
from django.core.cache import DEFAULT_CACHE_ALIAS, caches
-from django.core.exceptions import SynchronousOnlyOperation
+from django.core.exceptions import ImproperlyConfigured, SynchronousOnlyOperation
+from django.http import HttpResponse
from django.test import SimpleTestCase
from django.utils.asyncio import async_unsafe
+from django.views.generic.base import View
from .models import SimpleModel
@@ -72,3 +75,66 @@ class AsyncUnsafeTest(SimpleTestCase):
self.dangerous_method()
except SynchronousOnlyOperation:
self.fail("SynchronousOnlyOperation should not be raised.")
+
+
+class SyncView(View):
+ def get(self, request, *args, **kwargs):
+ return HttpResponse("Hello (sync) world!")
+
+
+class AsyncView(View):
+ async def get(self, request, *args, **kwargs):
+ return HttpResponse("Hello (async) world!")
+
+
+class ViewTests(SimpleTestCase):
+ def test_views_are_correctly_marked(self):
+ tests = [
+ (SyncView, False),
+ (AsyncView, True),
+ ]
+ for view_cls, is_async in tests:
+ with self.subTest(view_cls=view_cls, is_async=is_async):
+ self.assertIs(view_cls.view_is_async, is_async)
+ callback = view_cls.as_view()
+ self.assertIs(asyncio.iscoroutinefunction(callback), is_async)
+
+ def test_mixed_views_raise_error(self):
+ class MixedView(View):
+ def get(self, request, *args, **kwargs):
+ return HttpResponse("Hello (mixed) world!")
+
+ async def post(self, request, *args, **kwargs):
+ return HttpResponse("Hello (mixed) world!")
+
+ msg = (
+ f"{MixedView.__qualname__} HTTP handlers must either be all sync or all "
+ "async."
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
+ MixedView.as_view()
+
+ def test_options_handler_responds_correctly(self):
+ tests = [
+ (SyncView, False),
+ (AsyncView, True),
+ ]
+ for view_cls, is_coroutine in tests:
+ with self.subTest(view_cls=view_cls, is_coroutine=is_coroutine):
+ instance = view_cls()
+ response = instance.options(None)
+ self.assertIs(
+ asyncio.iscoroutine(response),
+ is_coroutine,
+ )
+ if is_coroutine:
+ response = asyncio.run(response)
+
+ self.assertIsInstance(response, HttpResponse)
+
+ def test_base_view_class_is_sync(self):
+ """
+ View and by extension any subclasses that don't define handlers are
+ sync.
+ """
+ self.assertIs(View.view_is_async, False)