From 51e44eaf84eec5939501858df623247cf814b66e Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 10 Jan 2024 14:23:10 +0200 Subject: [PATCH] Return a copy of the respnse from cache --- redis/_cache.py | 3 ++- tests/test_asyncio/test_cache.py | 11 +++++++++++ tests/test_cache.py | 12 ++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/redis/_cache.py b/redis/_cache.py index 4255afb7a4..f8cc7d21bf 100644 --- a/redis/_cache.py +++ b/redis/_cache.py @@ -1,3 +1,4 @@ +import copy import random import time from collections import OrderedDict, defaultdict @@ -226,7 +227,7 @@ def get(self, command: str) -> ResponseT: self.delete(command) return self._update_access(command) - return self.cache[command]["response"] + return copy.deepcopy(self.cache[command]["response"]) def delete(self, command: str): """ diff --git a/tests/test_asyncio/test_cache.py b/tests/test_asyncio/test_cache.py index 098ede8d75..bf20337dfb 100644 --- a/tests/test_asyncio/test_cache.py +++ b/tests/test_asyncio/test_cache.py @@ -131,6 +131,17 @@ async def test_cache_blacklist(self, r): assert cache.get(("LLEN", "mylist")) is None assert cache.get(("LINDEX", "mylist", 1)) == b"bar" + @pytest.mark.parametrize("r", [{"cache": _LocalCache()}], indirect=True) + async def test_cache_return_copy(self, r): + r, cache = r + await r.lpush("mylist", "foo", "bar", "baz") + assert await r.lrange("mylist", 0, -1) == [b"baz", b"bar", b"foo"] + res = cache.get(("LRANGE", "mylist", 0, -1)) + assert res == [b"baz", b"bar", b"foo"] + res.append(b"new") + check = cache.get(("LRANGE", "mylist", 0, -1)) + assert check == [b"baz", b"bar", b"foo"] + @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") @pytest.mark.onlycluster diff --git a/tests/test_cache.py b/tests/test_cache.py index 570385a4b5..4eb5160ecc 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -15,6 +15,7 @@ def r(request): redis.Redis, request, protocol=3, client_cache=cache, **kwargs ) as client: yield client, cache + # client.flushdb() @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") @@ -134,6 +135,17 @@ def test_cache_blacklist(self, r): assert cache.get(("LLEN", "mylist")) is None assert cache.get(("LINDEX", "mylist", 1)) == b"bar" + @pytest.mark.parametrize("r", [{"cache": _LocalCache()}], indirect=True) + def test_cache_return_copy(self, r): + r, cache = r + r.lpush("mylist", "foo", "bar", "baz") + assert r.lrange("mylist", 0, -1) == [b"baz", b"bar", b"foo"] + res = cache.get(("LRANGE", "mylist", 0, -1)) + assert res == [b"baz", b"bar", b"foo"] + res.append(b"new") + check = cache.get(("LRANGE", "mylist", 0, -1)) + assert check == [b"baz", b"bar", b"foo"] + @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") @pytest.mark.onlycluster