forked from django/django
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtests.py
140 lines (114 loc) · 4.4 KB
/
tests.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import asyncio
import os
import sys
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 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
@skipIf(
sys.platform == "win32" and (3, 8, 0) < sys.version_info < (3, 8, 1),
"https://bugs.python.org/issue38563",
)
class CacheTest(SimpleTestCase):
def test_caches_local(self):
@async_to_sync
async def async_cache():
return caches[DEFAULT_CACHE_ALIAS]
cache_1 = async_cache()
cache_2 = async_cache()
self.assertIs(cache_1, cache_2)
@skipIf(
sys.platform == "win32" and (3, 8, 0) < sys.version_info < (3, 8, 1),
"https://bugs.python.org/issue38563",
)
class DatabaseConnectionTest(SimpleTestCase):
"""A database connection cannot be used in an async context."""
async def test_get_async_connection(self):
with self.assertRaises(SynchronousOnlyOperation):
list(SimpleModel.objects.all())
@skipIf(
sys.platform == "win32" and (3, 8, 0) < sys.version_info < (3, 8, 1),
"https://bugs.python.org/issue38563",
)
class AsyncUnsafeTest(SimpleTestCase):
"""
async_unsafe decorator should work correctly and returns the correct
message.
"""
@async_unsafe
def dangerous_method(self):
return True
async def test_async_unsafe(self):
# async_unsafe decorator catches bad access and returns the right
# message.
msg = (
"You cannot call this from an async context - use a thread or "
"sync_to_async."
)
with self.assertRaisesMessage(SynchronousOnlyOperation, msg):
self.dangerous_method()
@mock.patch.dict(os.environ, {"DJANGO_ALLOW_ASYNC_UNSAFE": "true"})
@async_to_sync # mock.patch() is not async-aware.
async def test_async_unsafe_suppressed(self):
# Decorator doesn't trigger check when the environment variable to
# suppress it is set.
try:
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)