Skip to content

Commit 4d5462b

Browse files
committed
make test cases reusable for cluster
(cherry picked from commit a0ae7c9)
1 parent ffa2960 commit 4d5462b

File tree

7 files changed

+131
-1210
lines changed

7 files changed

+131
-1210
lines changed

tests/test_backend.py

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from django_valkey.cache import ValkeyCache
1717
from django_valkey.client import ShardClient, herd
18+
from django_valkey.cluster_cache.client import DefaultClusterClient
1819
from django_valkey.serializers.json import JSONSerializer
1920
from django_valkey.serializers.msgpack import MSGPackSerializer
2021
from django_valkey.serializers.pickle import PickleSerializer
@@ -99,7 +100,7 @@ def test_unicode_keys(self, cache: ValkeyCache):
99100
res = cache.get("ключ")
100101
assert res == "value"
101102

102-
def test_save_and_integer(self, cache: ValkeyCache):
103+
def test_save_an_integer(self, cache: ValkeyCache):
103104
cache.set("test_key", 2)
104105
res = cache.get("test_key", "Foo")
105106

@@ -223,7 +224,9 @@ def test_get_many(self, cache: ValkeyCache):
223224
assert res == {"a": 1, "b": 2, "c": 3}
224225

225226
def test_mget(self, cache: ValkeyCache):
226-
if isinstance(cache.client, ShardClient):
227+
if isinstance(cache.client, ShardClient) or isinstance(
228+
cache.client, DefaultClusterClient
229+
):
227230
pytest.skip()
228231
cache.set("a", 1)
229232
cache.set("b", 2)
@@ -240,13 +243,28 @@ def test_get_many_unicode(self, cache: ValkeyCache):
240243
res = cache.get_many(["a", "ب", "c"])
241244
assert res == {"a": "1", "ب": "2", "c": "الف"}
242245

246+
def test_mget_unicode(self, cache: ValkeyCache):
247+
if isinstance(cache.client, ShardClient) or isinstance(
248+
cache.client, DefaultClusterClient
249+
):
250+
pytest.skip()
251+
252+
cache.set("fooa", "1")
253+
cache.set("fooب", "2")
254+
cache.set("fooc", "الف")
255+
256+
res = cache.mget(["fooa", "fooب", "fooc"])
257+
assert res == {"fooa": "1", "fooب": "2", "fooc": "الف"}
258+
243259
def test_set_many(self, cache: ValkeyCache):
244260
cache.set_many({"a": 1, "b": 2, "c": 3})
245261
res = cache.get_many(["a", "b", "c"])
246262
assert res == {"a": 1, "b": 2, "c": 3}
247263

248264
def test_mset(self, cache: ValkeyCache):
249-
if isinstance(cache.client, ShardClient):
265+
if isinstance(cache.client, ShardClient) or isinstance(
266+
cache.client, DefaultClusterClient
267+
):
250268
pytest.skip()
251269
cache.mset({"a": 1, "b": 2, "c": 3})
252270
res = cache.mget(["a", "b", "c"])
@@ -518,6 +536,9 @@ def test_ttl_incr_version_no_timeout(self, cache: ValkeyCache):
518536
assert my_value == "hello world!"
519537

520538
def test_delete_pattern(self, cache: ValkeyCache):
539+
if isinstance(cache.client, DefaultClusterClient):
540+
pytest.skip("cluster client has a specific test")
541+
521542
for key in ["foo-aa", "foo-ab", "foo-bb", "foo-bc"]:
522543
cache.set(key, "foo")
523544

@@ -532,6 +553,9 @@ def test_delete_pattern(self, cache: ValkeyCache):
532553

533554
@patch("django_valkey.cache.ValkeyCache.client")
534555
def test_delete_pattern_with_custom_count(self, client_mock, cache: ValkeyCache):
556+
if isinstance(cache.client, DefaultClusterClient):
557+
pytest.skip("cluster client has a specific test")
558+
535559
for key in ["foo-aa", "foo-ab", "foo-bb", "foo-bc"]:
536560
cache.set(key, "foo")
537561

@@ -547,6 +571,9 @@ def test_delete_pattern_with_settings_default_scan_count(
547571
cache: ValkeyCache,
548572
settings: SettingsWrapper,
549573
):
574+
if isinstance(cache.client, DefaultClusterClient):
575+
pytest.skip("cluster client has a specific test")
576+
550577
for key in ["foo-aa", "foo-ab", "foo-bb", "foo-bc"]:
551578
cache.set(key, "foo")
552579
expected_count = settings.DJANGO_VALKEY_SCAN_ITERSIZE
@@ -715,6 +742,11 @@ def test_lock(self, cache: ValkeyCache):
715742
lock.release()
716743
assert not cache.has_key("foobar")
717744

745+
def test_lock_context_manager(self, cache: ValkeyCache):
746+
with cache.lock("foobar"):
747+
assert cache.has_key("foobar")
748+
assert not cache.has_key("foobar")
749+
718750
def test_lock_released_by_thread(self, cache: ValkeyCache):
719751
lock = cache.lock("foobar", thread_local=False)
720752
lock.acquire(blocking=True)
@@ -964,6 +996,9 @@ def test_sinter(self, cache: ValkeyCache):
964996
if isinstance(cache.client, ShardClient):
965997
pytest.skip("ShardClient doesn't support sinter")
966998

999+
if isinstance(cache.client, DefaultClusterClient):
1000+
pytest.skip("cluster client has a specific test")
1001+
9671002
cache.sadd("foo1", "bar1", "bar2")
9681003
cache.sadd("foo2", "bar2", "bar3")
9691004
assert cache.sinter("foo1", "foo2") == {"bar2"}
@@ -972,6 +1007,9 @@ def test_interstore(self, cache: ValkeyCache):
9721007
if isinstance(cache.client, ShardClient):
9731008
pytest.skip("ShardClient doesn't support sinterstore")
9741009

1010+
if isinstance(cache.client, DefaultClusterClient):
1011+
pytest.skip("cluster client has a specific test")
1012+
9751013
cache.sadd("foo1", "bar1", "bar2")
9761014
cache.sadd("foo2", "bar2", "bar3")
9771015
assert cache.sinterstore("foo3", "foo1", "foo2") == 1
@@ -1066,6 +1104,9 @@ def test_smove(self, cache: ValkeyCache):
10661104
# if isinstance(cache.client, ShardClient):
10671105
# pytest.skip("ShardClient doesn't support get_client")
10681106

1107+
if isinstance(cache.client, DefaultClusterClient):
1108+
pytest.skip("cluster client has a specific test")
1109+
10691110
cache.sadd("foo1", "bar1", "bar2")
10701111
cache.sadd("foo2", "bar2", "bar3")
10711112
assert cache.smove("foo1", "foo2", "bar1") is True
@@ -1130,6 +1171,9 @@ def test_sunion(self, cache: ValkeyCache):
11301171
if isinstance(cache.client, ShardClient):
11311172
pytest.skip("ShardClient doesn't support sunion")
11321173

1174+
if isinstance(cache.client, DefaultClusterClient):
1175+
pytest.skip("cluster client has a specific test")
1176+
11331177
cache.sadd("foo1", "bar1", "bar2")
11341178
cache.sadd("foo2", "bar2", "bar3")
11351179
assert cache.sunion("foo1", "foo2") == {"bar1", "bar2", "bar3"}
@@ -1138,6 +1182,9 @@ def test_sunionstore(self, cache: ValkeyCache):
11381182
if isinstance(cache.client, ShardClient):
11391183
pytest.skip("ShardClient doesn't support sunionstore")
11401184

1185+
if isinstance(cache.client, DefaultClusterClient):
1186+
pytest.skip("cluster client has a specific test")
1187+
11411188
cache.sadd("foo1", "bar1", "bar2")
11421189
cache.sadd("foo2", "bar2", "bar3")
11431190
assert cache.sunionstore("foo3", "foo1", "foo2") == 3

tests/test_cache_options.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
from typing import cast
44

55
import pytest
6-
from django.core.cache import caches
76
from pytest import LogCaptureFixture
87
from pytest_django.fixtures import SettingsWrapper
8+
9+
from django.core.cache import caches, cache as default_cache
10+
911
from valkey.exceptions import ConnectionError
1012

1113
from django_valkey.cache import ValkeyCache
1214
from django_valkey.client import ShardClient
15+
from django_valkey.cluster_cache.client import DefaultClusterClient
1316

1417

1518
def make_key(key: str, prefix: str, version: str) -> str:
@@ -31,13 +34,21 @@ def ignore_exceptions_cache(settings: SettingsWrapper) -> ValkeyCache:
3134
return cast(ValkeyCache, caches["doesnotexist"])
3235

3336

37+
@pytest.mark.skipif(
38+
isinstance(default_cache.client, DefaultClusterClient),
39+
reason="cluster client doesn't support ignore exception",
40+
)
3441
def test_get_django_omit_exceptions_many_returns_default_arg(
3542
ignore_exceptions_cache: ValkeyCache,
3643
):
3744
assert ignore_exceptions_cache._ignore_exceptions is True
3845
assert ignore_exceptions_cache.get_many(["key1", "key2", "key3"]) == {}
3946

4047

48+
@pytest.mark.skipif(
49+
isinstance(default_cache.client, DefaultClusterClient),
50+
reason="cluster client doesn't support ignore exception",
51+
)
4152
def test_get_django_omit_exceptions(
4253
caplog: LogCaptureFixture, ignore_exceptions_cache: ValkeyCache
4354
):
@@ -55,6 +66,10 @@ def test_get_django_omit_exceptions(
5566
)
5667

5768

69+
@pytest.mark.skipif(
70+
isinstance(default_cache.client, DefaultClusterClient),
71+
reason="cluster client doesn't support ignore exception",
72+
)
5873
def test_get_django_omit_exceptions_priority_1(settings: SettingsWrapper):
5974
caches_setting = copy.deepcopy(settings.CACHES)
6075
caches_setting["doesnotexist"]["OPTIONS"]["IGNORE_EXCEPTIONS"] = True
@@ -65,6 +80,10 @@ def test_get_django_omit_exceptions_priority_1(settings: SettingsWrapper):
6580
assert cache.get("key") is None
6681

6782

83+
@pytest.mark.skipif(
84+
isinstance(default_cache.client, DefaultClusterClient),
85+
reason="cluster client doesn't support ignore exception",
86+
)
6887
def test_get_django_omit_exceptions_priority_2(settings: SettingsWrapper):
6988
caches_setting = copy.deepcopy(settings.CACHES)
7089
caches_setting["doesnotexist"]["OPTIONS"]["IGNORE_EXCEPTIONS"] = False
@@ -113,6 +132,10 @@ def test_iter_keys(
113132
with_prefix_cache.set("b", "2")
114133
assert list(key_prefix_cache.iter_keys("*")) == ["a"]
115134

135+
@pytest.mark.skipif(
136+
isinstance(default_cache.client, DefaultClusterClient),
137+
reason="cluster client doesn't support ignore exception",
138+
)
116139
def test_keys(self, key_prefix_cache: ValkeyCache, with_prefix_cache: ValkeyCache):
117140
key_prefix_cache.set("a", "1")
118141
with_prefix_cache.set("b", "2")
@@ -121,6 +144,10 @@ def test_keys(self, key_prefix_cache: ValkeyCache, with_prefix_cache: ValkeyCach
121144
assert "b" not in keys
122145

123146

147+
@pytest.mark.skipif(
148+
isinstance(default_cache.client, DefaultClusterClient),
149+
reason="cluster client doesn't support ignore exception",
150+
)
124151
def test_custom_key_function(cache: ValkeyCache, settings: SettingsWrapper):
125152
caches_setting = copy.deepcopy(settings.CACHES)
126153
caches_setting["default"]["KEY_FUNCTION"] = "tests.test_cache_options.make_key"

tests/test_client.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
from unittest.mock import Mock, call, patch
33

44
import pytest
5-
from django.core.cache import DEFAULT_CACHE_ALIAS
65
from pytest_django.fixtures import SettingsWrapper
76
from pytest_mock import MockerFixture
87

8+
from django.core.cache import DEFAULT_CACHE_ALIAS, cache as default_cache
9+
910
from django_valkey.cache import ValkeyCache
1011
from django_valkey.client import DefaultClient, ShardClient
1112

@@ -58,9 +59,12 @@ def test_close_disconnect_client_options(
5859
assert mock.called
5960

6061

62+
@pytest.mark.skipif(
63+
not isinstance(default_cache.client, DefaultClient), reason="shard only test"
64+
)
6165
class TestDefaultClient:
62-
@patch("tests.test_client.DefaultClient.get_client")
63-
@patch("tests.test_client.DefaultClient.__init__", return_value=None)
66+
@patch("django_valkey.base_client.ClientCommands.get_client")
67+
@patch("django_valkey.base_client.BaseClient.__init__", return_value=None)
6468
def test_delete_pattern_calls_get_client_given_no_client(
6569
self, init_mock, get_client_mock
6670
):
@@ -71,9 +75,9 @@ def test_delete_pattern_calls_get_client_given_no_client(
7175
client.delete_pattern(pattern="foo*")
7276
get_client_mock.assert_called_once_with(write=True, tried=None)
7377

74-
@patch("tests.test_client.DefaultClient.make_pattern")
75-
@patch("tests.test_client.DefaultClient.get_client", return_value=Mock())
76-
@patch("tests.test_client.DefaultClient.__init__", return_value=None)
78+
@patch("django_valkey.base_client.BaseClient.make_pattern")
79+
@patch("django_valkey.base_client.ClientCommands.get_client", return_value=Mock())
80+
@patch("django_valkey.base_client.BaseClient.__init__", return_value=None)
7781
def test_delete_pattern_calls_make_pattern(
7882
self, init_mock, get_client_mock, make_pattern_mock
7983
):
@@ -87,9 +91,9 @@ def test_delete_pattern_calls_make_pattern(
8791
kwargs = {"version": None, "prefix": None}
8892
make_pattern_mock.assert_called_once_with("foo*", **kwargs)
8993

90-
@patch("tests.test_client.DefaultClient.make_pattern")
91-
@patch("tests.test_client.DefaultClient.get_client", return_value=Mock())
92-
@patch("tests.test_client.DefaultClient.__init__", return_value=None)
94+
@patch("django_valkey.base_client.BaseClient.make_pattern")
95+
@patch("django_valkey.base_client.ClientCommands.get_client", return_value=Mock())
96+
@patch("django_valkey.base_client.BaseClient.__init__", return_value=None)
9397
def test_delete_pattern_calls_scan_iter_with_count_if_itersize_given(
9498
self, init_mock, get_client_mock, make_pattern_mock
9599
):
@@ -104,9 +108,9 @@ def test_delete_pattern_calls_scan_iter_with_count_if_itersize_given(
104108
count=90210, match=make_pattern_mock.return_value
105109
)
106110

107-
@patch("tests.test_client.DefaultClient.make_pattern")
108-
@patch("tests.test_client.DefaultClient.get_client", return_value=Mock())
109-
@patch("tests.test_client.DefaultClient.__init__", return_value=None)
111+
@patch("django_valkey.base_client.BaseClient.make_pattern")
112+
@patch("django_valkey.base_client.ClientCommands.get_client", return_value=Mock())
113+
@patch("django_valkey.base_client.BaseClient.__init__", return_value=None)
110114
def test_delete_pattern_calls_pipeline_delete_and_execute(
111115
self, init_mock, get_client_mock, make_pattern_mock
112116
):
@@ -127,6 +131,9 @@ def test_delete_pattern_calls_pipeline_delete_and_execute(
127131
get_client_mock.return_value.pipeline.return_value.execute.assert_called_once()
128132

129133

134+
@pytest.mark.skipif(
135+
not isinstance(default_cache.client, ShardClient), reason="shard only test"
136+
)
130137
class TestShardClient:
131138
CLIENT_METHODS_FOR_MOCK = {
132139
"add",
@@ -166,8 +173,8 @@ def connection(self, mocker):
166173

167174
yield connection
168175

169-
@patch("tests.test_client.ShardClient.make_pattern")
170-
@patch("tests.test_client.ShardClient.__init__", return_value=None)
176+
@patch("django_valkey.base_client.BaseClient.make_pattern")
177+
@patch("django_valkey.client.sharded.ShardClient.__init__", return_value=None)
171178
def test_delete_pattern_calls_scan_iter_with_count_if_itersize_given(
172179
self,
173180
init_mock,

tests/test_session.py

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@
33
from datetime import timedelta
44
from typing import Optional, Type
55

6-
import django
7-
import pytest
86
from django.conf import settings
97
from django.contrib.sessions.backends.base import SessionBase
108
from django.contrib.sessions.backends.cache import SessionStore as CacheSession
11-
from django.core.cache import DEFAULT_CACHE_ALIAS, caches
129
from django.test import override_settings
1310
from django.utils import timezone
1411

15-
from django_valkey.serializers.msgpack import MSGPackSerializer
1612

1713
SessionType = Type[SessionBase]
1814

@@ -304,27 +300,23 @@ def test_decode_failure_logged_to_security(self):
304300
self.assertIn("corrupted", cm.output[0])
305301

306302
def test_actual_expiry(self):
307-
# this doesn't work with JSONSerializer (serializing timedelta)
308-
with override_settings(
309-
SESSION_SERIALIZER="django.contrib.sessions.serializers.PickleSerializer"
310-
):
311-
self.session = self.backend() # reinitialize after overriding settings
312-
313-
# Regression test for #19200
314-
old_session_key = None
315-
new_session_key = None
316-
try:
317-
self.session["foo"] = "bar"
318-
self.session.set_expiry(-timedelta(seconds=10))
319-
self.session.save()
320-
old_session_key = self.session.session_key
321-
# With an expiry date in the past, the session expires instantly.
322-
new_session = self.backend(self.session.session_key)
323-
new_session_key = new_session.session_key
324-
self.assertNotIn("foo", new_session)
325-
finally:
326-
self.session.delete(old_session_key)
327-
self.session.delete(new_session_key)
303+
self.session = self.backend() # reinitialize after overriding settings
304+
305+
# Regression test for #19200
306+
old_session_key = None
307+
new_session_key = None
308+
try:
309+
self.session["foo"] = "bar"
310+
self.session.set_expiry(-timedelta(seconds=10))
311+
self.session.save()
312+
old_session_key = self.session.session_key
313+
# With an expiry date in the past, the session expires instantly.
314+
new_session = self.backend(self.session.session_key)
315+
new_session_key = new_session.session_key
316+
self.assertNotIn("foo", new_session)
317+
finally:
318+
self.session.delete(old_session_key)
319+
self.session.delete(new_session_key)
328320

329321
def test_session_load_does_not_create_record(self):
330322
"""
@@ -366,14 +358,3 @@ def test_session_save_does_not_resurrect_session_logged_out_in_other_context(sel
366358

367359
class SessionTests(SessionTestsMixin, unittest.TestCase):
368360
backend = CacheSession
369-
370-
@pytest.mark.skipif(
371-
django.VERSION >= (4, 2),
372-
reason="PickleSerializer is removed as of https://code.djangoproject.com/ticket/29708",
373-
)
374-
def test_actual_expiry(self):
375-
if isinstance(
376-
caches[DEFAULT_CACHE_ALIAS].client._serializer, MSGPackSerializer
377-
):
378-
self.skipTest("msgpack serializer doesn't support datetime serialization")
379-
super().test_actual_expiry()

0 commit comments

Comments
 (0)