diff options
author | Carlton Gibson <carlton.gibson@noumenal.es> | 2022-04-07 07:05:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-07 07:05:59 +0200 |
commit | 9ffd4eae2ce7a7100c98f681e2b6ab818df384a4 (patch) | |
tree | 2cc678b6feff9f187517439bf2856a8702c1f356 /tests/async | |
parent | 2ee4caf56b8e000cabbb73ad81ff05738d6d0a35 (diff) | |
download | django-9ffd4eae2ce7a7100c98f681e2b6ab818df384a4.tar.gz |
Fixed #33611 -- Allowed View subclasses to define async method handlers.
Diffstat (limited to 'tests/async')
-rw-r--r-- | tests/async/tests.py | 68 |
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) |