django/tests/decorators/test_cache.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

231 lines
8.2 KiB
Python
Raw Permalink Normal View History

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
from django.views.decorators.cache import cache_control, cache_page, never_cache
class HttpRequestProxy:
def __init__(self, request):
self._request = request
def __getattr__(self, attr):
"""Proxy to the underlying HttpRequest object."""
return getattr(self._request, attr)
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")
def a_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):
MyClass().a_view(request)
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"))
def a_view(self, request):
return HttpResponse()
request = HttpRequest()
response = MyClass().a_view(HttpRequestProxy(request))
self.assertEqual(response.headers["Cache-Control"], "a=b")
def test_cache_control_empty_decorator(self):
@cache_control()
def a_view(request):
return HttpResponse()
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):
return HttpResponse()
response = a_view(HttpRequest())
cache_control_items = response.get("Cache-Control").split(", ")
self.assertEqual(
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):
def my_view(request):
return "response"
my_view_cached = cache_page(123)(my_view)
self.assertEqual(my_view_cached(HttpRequest()), "response")
my_view_cached2 = cache_page(123, key_prefix="test")(my_view)
self.assertEqual(my_view_cached2(HttpRequest()), "response")
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
def a_view(request):
return HttpResponse()
mocked_time.return_value = 1167616461.0
response = a_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",
)
@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):
return HttpResponse(headers={"Expires": "tomorrow"})
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
def a_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):
MyClass().a_view(request)
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)
def a_view(self, request):
return HttpResponse()
request = HttpRequest()
response = MyClass().a_view(HttpRequestProxy(request))
self.assertIn("Cache-Control", response.headers)
self.assertIn("Expires", response.headers)