|
@@ -1,5 +1,7 @@
|
|
|
from unittest import mock
|
|
|
|
|
|
+from asgiref.sync import iscoroutinefunction
|
|
|
+
|
|
|
from django.http import HttpRequest, HttpResponse
|
|
|
from django.test import SimpleTestCase
|
|
|
from django.utils.decorators import method_decorator
|
|
@@ -16,6 +18,20 @@ class HttpRequestProxy:
|
|
|
|
|
|
|
|
|
class CacheControlDecoratorTest(SimpleTestCase):
|
|
|
+ def test_wrapped_sync_function_is_not_coroutine_function(self):
|
|
|
+ def sync_view(request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ wrapped_view = cache_control()(sync_view)
|
|
|
+ self.assertIs(iscoroutinefunction(wrapped_view), False)
|
|
|
+
|
|
|
+ def test_wrapped_async_function_is_coroutine_function(self):
|
|
|
+ async def async_view(request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ wrapped_view = cache_control()(async_view)
|
|
|
+ self.assertIs(iscoroutinefunction(wrapped_view), True)
|
|
|
+
|
|
|
def test_cache_control_decorator_http_request(self):
|
|
|
class MyClass:
|
|
|
@cache_control(a="b")
|
|
@@ -32,6 +48,22 @@ class CacheControlDecoratorTest(SimpleTestCase):
|
|
|
with self.assertRaisesMessage(TypeError, msg):
|
|
|
MyClass().a_view(HttpRequestProxy(request))
|
|
|
|
|
|
+ async def test_cache_control_decorator_http_request_async_view(self):
|
|
|
+ class MyClass:
|
|
|
+ @cache_control(a="b")
|
|
|
+ async def async_view(self, request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ msg = (
|
|
|
+ "cache_control didn't receive an HttpRequest. If you are decorating a "
|
|
|
+ "classmethod, be sure to use @method_decorator."
|
|
|
+ )
|
|
|
+ request = HttpRequest()
|
|
|
+ with self.assertRaisesMessage(TypeError, msg):
|
|
|
+ await MyClass().async_view(request)
|
|
|
+ with self.assertRaisesMessage(TypeError, msg):
|
|
|
+ await MyClass().async_view(HttpRequestProxy(request))
|
|
|
+
|
|
|
def test_cache_control_decorator_http_request_proxy(self):
|
|
|
class MyClass:
|
|
|
@method_decorator(cache_control(a="b"))
|
|
@@ -50,6 +82,14 @@ class CacheControlDecoratorTest(SimpleTestCase):
|
|
|
response = a_view(HttpRequest())
|
|
|
self.assertEqual(response.get("Cache-Control"), "")
|
|
|
|
|
|
+ async def test_cache_control_empty_decorator_async_view(self):
|
|
|
+ @cache_control()
|
|
|
+ async def async_view(request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ response = await async_view(HttpRequest())
|
|
|
+ self.assertEqual(response.get("Cache-Control"), "")
|
|
|
+
|
|
|
def test_cache_control_full_decorator(self):
|
|
|
@cache_control(max_age=123, private=True, public=True, custom=456)
|
|
|
def a_view(request):
|
|
@@ -61,6 +101,17 @@ class CacheControlDecoratorTest(SimpleTestCase):
|
|
|
set(cache_control_items), {"max-age=123", "private", "public", "custom=456"}
|
|
|
)
|
|
|
|
|
|
+ async def test_cache_control_full_decorator_async_view(self):
|
|
|
+ @cache_control(max_age=123, private=True, public=True, custom=456)
|
|
|
+ async def async_view(request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ response = await async_view(HttpRequest())
|
|
|
+ cache_control_items = response.get("Cache-Control").split(", ")
|
|
|
+ self.assertEqual(
|
|
|
+ set(cache_control_items), {"max-age=123", "private", "public", "custom=456"}
|
|
|
+ )
|
|
|
+
|
|
|
|
|
|
class CachePageDecoratorTest(SimpleTestCase):
|
|
|
def test_cache_page(self):
|
|
@@ -74,6 +125,20 @@ class CachePageDecoratorTest(SimpleTestCase):
|
|
|
|
|
|
|
|
|
class NeverCacheDecoratorTest(SimpleTestCase):
|
|
|
+ def test_wrapped_sync_function_is_not_coroutine_function(self):
|
|
|
+ def sync_view(request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ wrapped_view = never_cache(sync_view)
|
|
|
+ self.assertIs(iscoroutinefunction(wrapped_view), False)
|
|
|
+
|
|
|
+ def test_wrapped_async_function_is_coroutine_function(self):
|
|
|
+ async def async_view(request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ wrapped_view = never_cache(async_view)
|
|
|
+ self.assertIs(iscoroutinefunction(wrapped_view), True)
|
|
|
+
|
|
|
@mock.patch("time.time")
|
|
|
def test_never_cache_decorator_headers(self, mocked_time):
|
|
|
@never_cache
|
|
@@ -91,6 +156,20 @@ class NeverCacheDecoratorTest(SimpleTestCase):
|
|
|
"max-age=0, no-cache, no-store, must-revalidate, private",
|
|
|
)
|
|
|
|
|
|
+ @mock.patch("time.time")
|
|
|
+ async def test_never_cache_decorator_headers_async_view(self, mocked_time):
|
|
|
+ @never_cache
|
|
|
+ async def async_view(request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ mocked_time.return_value = 1167616461.0
|
|
|
+ response = await async_view(HttpRequest())
|
|
|
+ self.assertEqual(response.headers["Expires"], "Mon, 01 Jan 2007 01:54:21 GMT")
|
|
|
+ self.assertEqual(
|
|
|
+ response.headers["Cache-Control"],
|
|
|
+ "max-age=0, no-cache, no-store, must-revalidate, private",
|
|
|
+ )
|
|
|
+
|
|
|
def test_never_cache_decorator_expires_not_overridden(self):
|
|
|
@never_cache
|
|
|
def a_view(request):
|
|
@@ -99,6 +178,14 @@ class NeverCacheDecoratorTest(SimpleTestCase):
|
|
|
response = a_view(HttpRequest())
|
|
|
self.assertEqual(response.headers["Expires"], "tomorrow")
|
|
|
|
|
|
+ async def test_never_cache_decorator_expires_not_overridden_async_view(self):
|
|
|
+ @never_cache
|
|
|
+ async def async_view(request):
|
|
|
+ return HttpResponse(headers={"Expires": "tomorrow"})
|
|
|
+
|
|
|
+ response = await async_view(HttpRequest())
|
|
|
+ self.assertEqual(response.headers["Expires"], "tomorrow")
|
|
|
+
|
|
|
def test_never_cache_decorator_http_request(self):
|
|
|
class MyClass:
|
|
|
@never_cache
|
|
@@ -115,6 +202,22 @@ class NeverCacheDecoratorTest(SimpleTestCase):
|
|
|
with self.assertRaisesMessage(TypeError, msg):
|
|
|
MyClass().a_view(HttpRequestProxy(request))
|
|
|
|
|
|
+ async def test_never_cache_decorator_http_request_async_view(self):
|
|
|
+ class MyClass:
|
|
|
+ @never_cache
|
|
|
+ async def async_view(self, request):
|
|
|
+ return HttpResponse()
|
|
|
+
|
|
|
+ request = HttpRequest()
|
|
|
+ msg = (
|
|
|
+ "never_cache didn't receive an HttpRequest. If you are decorating "
|
|
|
+ "a classmethod, be sure to use @method_decorator."
|
|
|
+ )
|
|
|
+ with self.assertRaisesMessage(TypeError, msg):
|
|
|
+ await MyClass().async_view(request)
|
|
|
+ with self.assertRaisesMessage(TypeError, msg):
|
|
|
+ await MyClass().async_view(HttpRequestProxy(request))
|
|
|
+
|
|
|
def test_never_cache_decorator_http_request_proxy(self):
|
|
|
class MyClass:
|
|
|
@method_decorator(never_cache)
|