Skip to content

Commit 5ccb7cc

Browse files
test: add more tests
1 parent d114305 commit 5ccb7cc

2 files changed

Lines changed: 89 additions & 0 deletions

File tree

apps/utils/tests/__init__.py

Whitespace-only changes.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import uuid
2+
from typing import Any
3+
4+
from django.core.cache import cache
5+
from django.test import RequestFactory, TestCase
6+
7+
from apps.utils.cache import (
8+
cache_current_request_property,
9+
cache_global_property,
10+
cache_serializer_result_per_object,
11+
)
12+
13+
14+
class CachingDecoratorsTestCase(TestCase):
15+
# ------------------------------------------------------------------------------------------------------------------
16+
def test_cache_global_property_caches_and_reuses_result(self):
17+
calls = {"count": 0}
18+
19+
@cache_global_property("global_settings_key", timeout=60)
20+
def get_settings():
21+
calls["count"] += 1
22+
return {"mode": "prod"}
23+
24+
# First call computes
25+
v1 = get_settings()
26+
assert v1 == {"mode": "prod"}
27+
assert calls["count"] == 1
28+
29+
# Second call should be served from cache (no increment)
30+
v2 = get_settings()
31+
assert v2 == {"mode": "prod"}
32+
assert calls["count"] == 1
33+
34+
# Manual invalidation -> should recompute once
35+
cache.delete("global_settings_key")
36+
v3 = get_settings()
37+
assert v3 == {"mode": "prod"}
38+
assert calls["count"] == 2
39+
40+
# ------------------------------------------------------------------------------------------------------------------
41+
def test_cache_current_request_property_per_request(self):
42+
rf = RequestFactory()
43+
calls = {"count": 0}
44+
45+
@cache_current_request_property("current_permissions")
46+
def get_perms(request):
47+
calls["count"] += 1
48+
return ["read", "write"]
49+
50+
# Request A: first call computes, second call uses request attribute cache
51+
req_a = rf.get("/sample")
52+
p1 = get_perms(req_a)
53+
p2 = get_perms(req_a)
54+
assert p1 == ["read", "write"]
55+
assert p2 == ["read", "write"]
56+
assert calls["count"] == 1 # only computed once for this request
57+
58+
# Request B: new request should trigger a new compute
59+
req_b = rf.get("/sample")
60+
p3 = get_perms(req_b)
61+
assert p3 == ["read", "write"]
62+
assert calls["count"] == 2
63+
64+
# ------------------------------------------------------------------------------------------------------------------
65+
def test_cache_serializer_is_per_serializer_instance(self):
66+
class DummyObj:
67+
def __init__(self, id_):
68+
self.id = id_
69+
70+
class DummySerializer:
71+
def __init__(self):
72+
self.calls = 0
73+
74+
@cache_serializer_result_per_object("current_membership")
75+
def get_dummy(self, obj: DummyObj) -> Any:
76+
self.calls += 1
77+
return {"obj": obj.id, "plan": "gold"}
78+
79+
# Ensure cache is bound to each serializer instance, not global
80+
ser1 = DummySerializer()
81+
ser2 = DummySerializer()
82+
obj = DummyObj(uuid.uuid4())
83+
84+
_ = ser1.get_dummy(obj) # compute in ser1
85+
assert ser1.calls == 1
86+
assert ser2.calls == 0
87+
88+
_ = ser2.get_dummy(obj) # compute again in ser2 (separate cache)
89+
assert ser2.calls == 1

0 commit comments

Comments
 (0)