diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 11b08c934e..a211e5d403 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -115,7 +115,9 @@ jobs: python-version: ['3.8', '3.11'] test-type: ['standalone', 'cluster'] connection-type: ['hiredis', 'plain'] - protocol: ['3'] + exclude: + - test-type: 'cluster' + connection-type: 'hiredis' env: ACTIONS_ALLOW_UNSECURE_COMMANDS: true name: RESP3 [${{ matrix.python-version }} ${{matrix.test-type}}-${{matrix.connection-type}}] @@ -134,9 +136,33 @@ jobs: pip install hiredis fi invoke devenv - sleep 5 # time to settle - invoke ${{matrix.test-type}}-tests - invoke ${{matrix.test-type}}-tests --uvloop + sleep 10 # time to settle + invoke ${{matrix.test-type}}-tests --protocol=3 + invoke ${{matrix.test-type}}-tests --uvloop --protocol=3 + + - uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: pytest-results-${{matrix.test-type}}-${{matrix.connection-type}}-${{matrix.python-version}}-resp3 + path: '${{matrix.test-type}}*results.xml' + + - name: Upload codecov coverage + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: false + + - name: View Test Results + uses: dorny/test-reporter@v1 + if: success() || failure() + continue-on-error: true + with: + name: Test Results ${{matrix.python-version}} ${{matrix.test-type}}-${{matrix.connection-type}}-resp3 + path: '*.xml' + reporter: java-junit + list-suites: all + list-tests: all + max-annotations: 10 + fail-on-error: 'false' build_and_test_package: name: Validate building and installing the package diff --git a/redis/_parsers/hiredis.py b/redis/_parsers/hiredis.py index a52dbbd013..c807bd903a 100644 --- a/redis/_parsers/hiredis.py +++ b/redis/_parsers/hiredis.py @@ -19,6 +19,11 @@ SERVER_CLOSED_CONNECTION_ERROR, ) +# Used to signal that hiredis-py does not have enough data to parse. +# Using `False` or `None` is not reliable, given that the parser can +# return `False` or `None` for legitimate reasons from RESP payloads. +NOT_ENOUGH_DATA = object() + class _HiredisReaderArgs(TypedDict, total=False): protocolError: Callable[[str], Exception] @@ -51,25 +56,26 @@ def on_connect(self, connection, **kwargs): "protocolError": InvalidResponse, "replyError": self.parse_error, "errors": connection.encoder.encoding_errors, + "notEnoughData": NOT_ENOUGH_DATA, } if connection.encoder.decode_responses: kwargs["encoding"] = connection.encoder.encoding self._reader = hiredis.Reader(**kwargs) - self._next_response = False + self._next_response = NOT_ENOUGH_DATA def on_disconnect(self): self._sock = None self._reader = None - self._next_response = False + self._next_response = NOT_ENOUGH_DATA def can_read(self, timeout): if not self._reader: raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR) - if self._next_response is False: + if self._next_response is NOT_ENOUGH_DATA: self._next_response = self._reader.gets() - if self._next_response is False: + if self._next_response is NOT_ENOUGH_DATA: return self.read_from_socket(timeout=timeout, raise_on_timeout=False) return True @@ -108,9 +114,9 @@ def read_response(self, disable_decoding=False): raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR) # _next_response might be cached from a can_read() call - if self._next_response is not False: + if self._next_response is not NOT_ENOUGH_DATA: response = self._next_response - self._next_response = False + self._next_response = NOT_ENOUGH_DATA return response if disable_decoding: @@ -118,7 +124,7 @@ def read_response(self, disable_decoding=False): else: response = self._reader.gets() - while response is False: + while response is NOT_ENOUGH_DATA: self.read_from_socket() if disable_decoding: response = self._reader.gets(False) @@ -156,6 +162,7 @@ def on_connect(self, connection): kwargs: _HiredisReaderArgs = { "protocolError": InvalidResponse, "replyError": self.parse_error, + "notEnoughData": NOT_ENOUGH_DATA, } if connection.encoder.decode_responses: kwargs["encoding"] = connection.encoder.encoding @@ -170,7 +177,7 @@ def on_disconnect(self): async def can_read_destructive(self): if not self._connected: raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR) - if self._reader.gets(): + if self._reader.gets() is not NOT_ENOUGH_DATA: return True try: async with async_timeout(0): @@ -200,7 +207,7 @@ async def read_response( response = self._reader.gets(False) else: response = self._reader.gets() - while response is False: + while response is NOT_ENOUGH_DATA: await self.read_from_socket() if disable_decoding: response = self._reader.gets(False) diff --git a/tests/test_asyncio/conftest.py b/tests/test_asyncio/conftest.py index cff239fa11..6e93407b4c 100644 --- a/tests/test_asyncio/conftest.py +++ b/tests/test_asyncio/conftest.py @@ -6,13 +6,11 @@ import pytest_asyncio import redis.asyncio as redis from packaging.version import Version -from redis._parsers import _AsyncHiredisParser, _AsyncRESP2Parser from redis.asyncio import Sentinel from redis.asyncio.client import Monitor from redis.asyncio.connection import Connection, parse_url from redis.asyncio.retry import Retry from redis.backoff import NoBackoff -from redis.utils import HIREDIS_AVAILABLE from tests.conftest import REDIS_INFO from .compat import mock @@ -28,41 +26,21 @@ async def _get_info(redis_url): @pytest_asyncio.fixture( params=[ pytest.param( - (True, _AsyncRESP2Parser), + (True,), marks=pytest.mark.skipif( 'config.REDIS_INFO["cluster_enabled"]', reason="cluster mode enabled" ), ), - (False, _AsyncRESP2Parser), - pytest.param( - (True, _AsyncHiredisParser), - marks=[ - pytest.mark.skipif( - 'config.REDIS_INFO["cluster_enabled"]', - reason="cluster mode enabled", - ), - pytest.mark.skipif( - not HIREDIS_AVAILABLE, reason="hiredis is not installed" - ), - ], - ), - pytest.param( - (False, _AsyncHiredisParser), - marks=pytest.mark.skipif( - not HIREDIS_AVAILABLE, reason="hiredis is not installed" - ), - ), + (False,), ], ids=[ - "single-python-parser", - "pool-python-parser", - "single-hiredis", - "pool-hiredis", + "single", + "pool", ], ) async def create_redis(request): """Wrapper around redis.create_redis.""" - single_connection, parser_cls = request.param + (single_connection,) = request.param teardown_clients = [] @@ -78,10 +56,9 @@ async def client_factory( cluster_mode = REDIS_INFO["cluster_enabled"] if not cluster_mode: single = kwargs.pop("single_connection_client", False) or single_connection - parser_class = kwargs.pop("parser_class", None) or parser_cls url_options = parse_url(url) url_options.update(kwargs) - pool = redis.ConnectionPool(parser_class=parser_class, **url_options) + pool = redis.ConnectionPool(**url_options) client = cls(connection_pool=pool) else: client = redis.RedisCluster.from_url(url, **kwargs) diff --git a/tests/test_asyncio/test_json.py b/tests/test_asyncio/test_json.py index cc98a55323..507afc5621 100644 --- a/tests/test_asyncio/test_json.py +++ b/tests/test_asyncio/test_json.py @@ -22,7 +22,7 @@ async def test_json_setbinarykey(decoded_r: redis.Redis): @pytest.mark.redismod async def test_json_setgetdeleteforget(decoded_r: redis.Redis): assert await decoded_r.json().set("foo", Path.root_path(), "bar") - assert_resp_response(decoded_r, await decoded_r.json().get("foo"), "bar", [["bar"]]) + assert await decoded_r.json().get("foo") == "bar" assert await decoded_r.json().get("baz") is None assert await decoded_r.json().delete("foo") == 1 assert await decoded_r.json().forget("foo") == 0 # second delete @@ -32,13 +32,13 @@ async def test_json_setgetdeleteforget(decoded_r: redis.Redis): @pytest.mark.redismod async def test_jsonget(decoded_r: redis.Redis): await decoded_r.json().set("foo", Path.root_path(), "bar") - assert_resp_response(decoded_r, await decoded_r.json().get("foo"), "bar", [["bar"]]) + assert await decoded_r.json().get("foo") == "bar" @pytest.mark.redismod async def test_json_get_jset(decoded_r: redis.Redis): assert await decoded_r.json().set("foo", Path.root_path(), "bar") - assert_resp_response(decoded_r, await decoded_r.json().get("foo"), "bar", [["bar"]]) + assert await decoded_r.json().get("foo") == "bar" assert await decoded_r.json().get("baz") is None assert 1 == await decoded_r.json().delete("foo") assert await decoded_r.exists("foo") == 0 @@ -47,10 +47,7 @@ async def test_json_get_jset(decoded_r: redis.Redis): @pytest.mark.redismod async def test_nonascii_setgetdelete(decoded_r: redis.Redis): assert await decoded_r.json().set("notascii", Path.root_path(), "hyvää-élève") - res = "hyvää-élève" - assert_resp_response( - decoded_r, await decoded_r.json().get("notascii", no_escape=True), res, [[res]] - ) + assert await decoded_r.json().get("notascii", no_escape=True) == "hyvää-élève" assert 1 == await decoded_r.json().delete("notascii") assert await decoded_r.exists("notascii") == 0 @@ -192,8 +189,7 @@ async def test_toggle(decoded_r: redis.Redis): async def test_strappend(decoded_r: redis.Redis): await decoded_r.json().set("jsonkey", Path.root_path(), "foo") assert 6 == await decoded_r.json().strappend("jsonkey", "bar") - res = await decoded_r.json().get("jsonkey", Path.root_path()) - assert_resp_response(decoded_r, res, "foobar", [["foobar"]]) + assert "foobar" == await decoded_r.json().get("jsonkey", Path.root_path()) @pytest.mark.redismod @@ -230,14 +226,12 @@ async def test_arrindex(decoded_r: redis.Redis): async def test_arrinsert(decoded_r: redis.Redis): await decoded_r.json().set("arr", Path.root_path(), [0, 4]) assert 5 == await decoded_r.json().arrinsert("arr", Path.root_path(), 1, *[1, 2, 3]) - res = [0, 1, 2, 3, 4] - assert_resp_response(decoded_r, await decoded_r.json().get("arr"), res, [[res]]) + assert await decoded_r.json().get("arr") == [0, 1, 2, 3, 4] # test prepends await decoded_r.json().set("val2", Path.root_path(), [5, 6, 7, 8, 9]) await decoded_r.json().arrinsert("val2", Path.root_path(), 0, ["some", "thing"]) - res = [["some", "thing"], 5, 6, 7, 8, 9] - assert_resp_response(decoded_r, await decoded_r.json().get("val2"), res, [[res]]) + assert await decoded_r.json().get("val2") == [["some", "thing"], 5, 6, 7, 8, 9] @pytest.mark.redismod @@ -255,7 +249,7 @@ async def test_arrpop(decoded_r: redis.Redis): assert 3 == await decoded_r.json().arrpop("arr", Path.root_path(), -1) assert 2 == await decoded_r.json().arrpop("arr", Path.root_path()) assert 0 == await decoded_r.json().arrpop("arr", Path.root_path(), 0) - assert_resp_response(decoded_r, await decoded_r.json().get("arr"), [1], [[[1]]]) + assert [1] == await decoded_r.json().get("arr") # test out of bounds await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) @@ -270,8 +264,7 @@ async def test_arrpop(decoded_r: redis.Redis): async def test_arrtrim(decoded_r: redis.Redis): await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) assert 3 == await decoded_r.json().arrtrim("arr", Path.root_path(), 1, 3) - res = await decoded_r.json().get("arr") - assert_resp_response(decoded_r, res, [1, 2, 3], [[[1, 2, 3]]]) + assert [1, 2, 3] == await decoded_r.json().get("arr") # <0 test, should be 0 equivalent await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) @@ -356,15 +349,14 @@ async def test_json_delete_with_dollar(decoded_r: redis.Redis): doc1 = {"a": 1, "nested": {"a": 2, "b": 3}} assert await decoded_r.json().set("doc1", "$", doc1) assert await decoded_r.json().delete("doc1", "$..a") == 2 - res = [{"nested": {"b": 3}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == [{"nested": {"b": 3}}] doc2 = {"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [True, "a", "b"]}} assert await decoded_r.json().set("doc2", "$", doc2) assert await decoded_r.json().delete("doc2", "$..a") == 1 - res = await decoded_r.json().get("doc2", "$") - res = [{"nested": {"b": [True, "a", "b"]}, "b": ["a", "b"]}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc2", "$"), res, [res]) + assert await decoded_r.json().get("doc2", "$") == [ + {"nested": {"b": [True, "a", "b"]}, "b": ["a", "b"]} + ] doc3 = [ { @@ -395,8 +387,7 @@ async def test_json_delete_with_dollar(decoded_r: redis.Redis): } ] ] - res = await decoded_r.json().get("doc3", "$") - assert_resp_response(decoded_r, res, doc3val, [doc3val]) + assert await decoded_r.json().get("doc3", "$") == doc3val # Test async default path assert await decoded_r.json().delete("doc3") == 1 @@ -410,14 +401,14 @@ async def test_json_forget_with_dollar(decoded_r: redis.Redis): doc1 = {"a": 1, "nested": {"a": 2, "b": 3}} assert await decoded_r.json().set("doc1", "$", doc1) assert await decoded_r.json().forget("doc1", "$..a") == 2 - res = [{"nested": {"b": 3}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == [{"nested": {"b": 3}}] doc2 = {"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [True, "a", "b"]}} assert await decoded_r.json().set("doc2", "$", doc2) assert await decoded_r.json().forget("doc2", "$..a") == 1 - res = [{"nested": {"b": [True, "a", "b"]}, "b": ["a", "b"]}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc2", "$"), res, [res]) + assert await decoded_r.json().get("doc2", "$") == [ + {"nested": {"b": [True, "a", "b"]}, "b": ["a", "b"]} + ] doc3 = [ { @@ -448,8 +439,7 @@ async def test_json_forget_with_dollar(decoded_r: redis.Redis): } ] ] - res = await decoded_r.json().get("doc3", "$") - assert_resp_response(decoded_r, res, doc3val, [doc3val]) + assert await decoded_r.json().get("doc3", "$") == doc3val # Test async default path assert await decoded_r.json().forget("doc3") == 1 @@ -473,14 +463,8 @@ async def test_json_mget_dollar(decoded_r: redis.Redis): {"a": 4, "b": 5, "nested": {"a": 6}, "c": None, "nested2": {"a": [None]}}, ) # Compare also to single JSON.GET - res = [1, 3, None] - assert_resp_response( - decoded_r, await decoded_r.json().get("doc1", "$..a"), res, [res] - ) - res = [4, 6, [None]] - assert_resp_response( - decoded_r, await decoded_r.json().get("doc2", "$..a"), res, [res] - ) + assert await decoded_r.json().get("doc1", "$..a") == [1, 3, None] + assert await decoded_r.json().get("doc2", "$..a") == [4, 6, [None]] # Test mget with single path assert await decoded_r.json().mget(["doc1"], "$..a") == [[1, 3, None]] @@ -539,7 +523,9 @@ async def test_numby_commands_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", "$", {"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]} ) - assert await decoded_r.json().numincrby("doc1", ".b[0].a", 3) == 5 + assert_resp_response( + decoded_r, await decoded_r.json().numincrby("doc1", ".b[0].a", 3), 5, [5] + ) # Test legacy NUMMULTBY await decoded_r.json().set( @@ -547,7 +533,9 @@ async def test_numby_commands_dollar(decoded_r: redis.Redis): ) with pytest.deprecated_call(): - assert await decoded_r.json().nummultby("doc1", ".b[0].a", 3) == 6 + assert_resp_response( + decoded_r, await decoded_r.json().nummultby("doc1", ".b[0].a", 3), 6, [6] + ) @pytest.mark.redismod @@ -559,13 +547,13 @@ async def test_strappend_dollar(decoded_r: redis.Redis): assert await decoded_r.json().strappend("doc1", "bar", "$..a") == [6, 8, None] res = [{"a": "foobar", "nested1": {"a": "hellobar"}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test single assert await decoded_r.json().strappend("doc1", "baz", "$.nested1.a") == [11] res = [{"a": "foobar", "nested1": {"a": "hellobarbaz"}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -574,7 +562,7 @@ async def test_strappend_dollar(decoded_r: redis.Redis): # Test multi assert await decoded_r.json().strappend("doc1", "bar", ".*.a") == 14 res = [{"a": "foobar", "nested1": {"a": "hellobarbazbar"}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing path with pytest.raises(exceptions.ResponseError): @@ -623,7 +611,7 @@ async def test_arrappend_dollar(decoded_r: redis.Redis): "nested2": {"a": 31}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test single assert await decoded_r.json().arrappend("doc1", "$.nested1.a", "baz") == [6] @@ -634,7 +622,7 @@ async def test_arrappend_dollar(decoded_r: redis.Redis): "nested2": {"a": 31}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -660,7 +648,7 @@ async def test_arrappend_dollar(decoded_r: redis.Redis): "nested2": {"a": 31}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test single assert await decoded_r.json().arrappend("doc1", ".nested1.a", "baz") == 6 res = [ @@ -670,7 +658,7 @@ async def test_arrappend_dollar(decoded_r: redis.Redis): "nested2": {"a": 31}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -699,7 +687,7 @@ async def test_arrinsert_dollar(decoded_r: redis.Redis): "nested2": {"a": 31}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test single assert await decoded_r.json().arrinsert("doc1", "$.nested1.a", -2, "baz") == [6] res = [ @@ -709,7 +697,7 @@ async def test_arrinsert_dollar(decoded_r: redis.Redis): "nested2": {"a": 31}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -778,7 +766,7 @@ async def test_arrpop_dollar(decoded_r: redis.Redis): assert await decoded_r.json().arrpop("doc1", "$..a", 1) == ['"foo"', None, None] res = [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -797,7 +785,7 @@ async def test_arrpop_dollar(decoded_r: redis.Redis): # Test multi (all paths are updated, but return result of last path) assert await decoded_r.json().arrpop("doc1", "..a", "1") == "null" res = [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # # Test missing key with pytest.raises(exceptions.ResponseError): @@ -818,15 +806,15 @@ async def test_arrtrim_dollar(decoded_r: redis.Redis): # Test multi assert await decoded_r.json().arrtrim("doc1", "$..a", "1", -1) == [0, 2, None] res = [{"a": [], "nested1": {"a": [None, "world"]}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res assert await decoded_r.json().arrtrim("doc1", "$..a", "1", "1") == [0, 1, None] res = [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test single assert await decoded_r.json().arrtrim("doc1", "$.nested1.a", 1, 0) == [0] res = [{"a": [], "nested1": {"a": []}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -849,7 +837,7 @@ async def test_arrtrim_dollar(decoded_r: redis.Redis): # Test single assert await decoded_r.json().arrtrim("doc1", ".nested1.a", "1", "1") == 1 res = [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -979,7 +967,7 @@ async def test_clear_dollar(decoded_r: redis.Redis): res = [ {"nested1": {"a": {}}, "a": [], "nested2": {"a": "claro"}, "nested3": {"a": {}}} ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test single await decoded_r.json().set( @@ -1001,13 +989,11 @@ async def test_clear_dollar(decoded_r: redis.Redis): "nested3": {"a": {"baz": 50}}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing path (async defaults to root) assert await decoded_r.json().clear("doc1") == 1 - assert_resp_response( - decoded_r, await decoded_r.json().get("doc1", "$"), [{}], [[{}]] - ) + assert await decoded_r.json().get("doc1", "$") == [{}] # Test missing key with pytest.raises(exceptions.ResponseError): @@ -1036,7 +1022,7 @@ async def test_toggle_dollar(decoded_r: redis.Redis): "nested3": {"a": False}, } ] - assert_resp_response(decoded_r, await decoded_r.json().get("doc1", "$"), res, [res]) + assert await decoded_r.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): diff --git a/tests/test_asyncio/test_timeseries.py b/tests/test_asyncio/test_timeseries.py index c93af1ea5b..0475c318ec 100644 --- a/tests/test_asyncio/test_timeseries.py +++ b/tests/test_asyncio/test_timeseries.py @@ -780,8 +780,12 @@ async def test_create_with_insertion_filters(decoded_r: redis.Redis): assert 1021 == await decoded_r.ts().add("time-series-1", 1021, 22.0) data_points = await decoded_r.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0), (1010, 11.0), (1020, 11.5), (1021, 22.0)] - assert expected_points == data_points + assert_resp_response( + decoded_r, + data_points, + [(1000, 1.0), (1010, 11.0), (1020, 11.5), (1021, 22.0)], + [[1000, 1.0], [1010, 11.0], [1020, 11.5], [1021, 22.0]], + ) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -800,8 +804,12 @@ async def test_alter_with_insertion_filters(decoded_r: redis.Redis): assert 1013 == await decoded_r.ts().add("time-series-1", 1015, 11.5) data_points = await decoded_r.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0), (1010, 11.0), (1013, 10.0)] - assert expected_points == data_points + assert_resp_response( + decoded_r, + data_points, + [(1000, 1.0), (1010, 11.0), (1013, 10.0)], + [[1000, 1.0], [1010, 11.0], [1013, 10.0]], + ) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -818,8 +826,7 @@ async def test_add_with_insertion_filters(decoded_r: redis.Redis): assert 1000 == await decoded_r.ts().add("time-series-1", 1004, 3.0) data_points = await decoded_r.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0)] - assert expected_points == data_points + assert_resp_response(decoded_r, data_points, [(1000, 1.0)], [[1000, 1.0]]) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -836,14 +843,12 @@ async def test_incrby_with_insertion_filters(decoded_r: redis.Redis): assert 1000 == await decoded_r.ts().incrby("time-series-1", 3.0, timestamp=1000) data_points = await decoded_r.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0)] - assert expected_points == data_points + assert_resp_response(decoded_r, data_points, [(1000, 1.0)], [[1000, 1.0]]) assert 1000 == await decoded_r.ts().incrby("time-series-1", 10.1, timestamp=1000) data_points = await decoded_r.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 11.1)] - assert expected_points == data_points + assert_resp_response(decoded_r, data_points, [(1000, 11.1)], [[1000, 11.1]]) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -860,11 +865,9 @@ async def test_decrby_with_insertion_filters(decoded_r: redis.Redis): assert 1000 == await decoded_r.ts().decrby("time-series-1", 3.0, timestamp=1000) data_points = await decoded_r.ts().range("time-series-1", "-", "+") - expected_points = [(1000, -1.0)] - assert expected_points == data_points + assert_resp_response(decoded_r, data_points, [(1000, -1.0)], [[1000, -1.0]]) assert 1000 == await decoded_r.ts().decrby("time-series-1", 10.1, timestamp=1000) data_points = await decoded_r.ts().range("time-series-1", "-", "+") - expected_points = [(1000, -11.1)] - assert expected_points == data_points + assert_resp_response(decoded_r, data_points, [(1000, -11.1)], [[1000, -11.1]]) diff --git a/tests/test_command_parser.py b/tests/test_command_parser.py index e3b44a147f..5c23a7096f 100644 --- a/tests/test_command_parser.py +++ b/tests/test_command_parser.py @@ -1,5 +1,6 @@ import pytest from redis._parsers import CommandsParser +from redis.utils import HIREDIS_AVAILABLE from .conftest import ( assert_resp_response, @@ -8,6 +9,9 @@ ) +# The response to COMMAND contains maps inside sets, which are not handled +# by the hiredis-py parser (see https://github.com/redis/hiredis-py/issues/188) +@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") class TestCommandsParser: def test_init_commands(self, r): commands_parser = CommandsParser(r) diff --git a/tests/test_commands.py b/tests/test_commands.py index d0071155ea..aab2a227ed 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -18,6 +18,7 @@ parse_info, ) from redis.client import EMPTY_RESPONSE, NEVER_DECODE +from redis.utils import HIREDIS_AVAILABLE from .conftest import ( _get_client, @@ -1841,7 +1842,14 @@ def test_tfunction_list(self, stack_r): assert len(functions) == 3 expected_names = [b"lib1", b"lib2", b"lib3"] - actual_names = [functions[0][13], functions[1][13], functions[2][13]] + if is_resp2_connection(stack_r): + actual_names = [functions[0][13], functions[1][13], functions[2][13]] + else: + actual_names = [ + functions[0][b"name"], + functions[1][b"name"], + functions[2][b"name"], + ] assert sorted(expected_names) == sorted(actual_names) assert stack_r.tfunction_delete("lib1") @@ -5009,6 +5017,9 @@ def test_command_getkeys(self, r): r, res, ["key1", "key2", "key3"], [b"key1", b"key2", b"key3"] ) + # The response to COMMAND contains maps inside sets, which are not handled + # by the hiredis-py parser (see https://github.com/redis/hiredis-py/issues/188) + @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") @skip_if_server_version_lt("2.8.13") def test_command(self, r): res = r.command() diff --git a/tests/test_json.py b/tests/test_json.py index 9996c898d4..a688464874 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -25,7 +25,7 @@ def test_json_setbinarykey(client): @pytest.mark.redismod def test_json_setgetdeleteforget(client): assert client.json().set("foo", Path.root_path(), "bar") - assert_resp_response(client, client.json().get("foo"), "bar", [["bar"]]) + assert client.json().get("foo") == "bar" assert client.json().get("baz") is None assert client.json().delete("foo") == 1 assert client.json().forget("foo") == 0 # second delete @@ -35,13 +35,13 @@ def test_json_setgetdeleteforget(client): @pytest.mark.redismod def test_jsonget(client): client.json().set("foo", Path.root_path(), "bar") - assert_resp_response(client, client.json().get("foo"), "bar", [["bar"]]) + assert client.json().get("foo") == "bar" @pytest.mark.redismod def test_json_get_jset(client): assert client.json().set("foo", Path.root_path(), "bar") - assert_resp_response(client, client.json().get("foo"), "bar", [["bar"]]) + assert client.json().get("foo") == "bar" assert client.json().get("baz") is None assert 1 == client.json().delete("foo") assert client.exists("foo") == 0 @@ -83,10 +83,7 @@ def test_json_merge(client): @pytest.mark.redismod def test_nonascii_setgetdelete(client): assert client.json().set("notascii", Path.root_path(), "hyvää-élève") - res = "hyvää-élève" - assert_resp_response( - client, client.json().get("notascii", no_escape=True), res, [[res]] - ) + assert client.json().get("notascii", no_escape=True) == "hyvää-élève" assert 1 == client.json().delete("notascii") assert client.exists("notascii") == 0 @@ -191,9 +188,7 @@ def test_toggle(client): def test_strappend(client): client.json().set("jsonkey", Path.root_path(), "foo") assert 6 == client.json().strappend("jsonkey", "bar") - assert_resp_response( - client, client.json().get("jsonkey", Path.root_path()), "foobar", [["foobar"]] - ) + assert "foobar" == client.json().get("jsonkey", Path.root_path()) @pytest.mark.redismod @@ -229,14 +224,12 @@ def test_arrindex(client): def test_arrinsert(client): client.json().set("arr", Path.root_path(), [0, 4]) assert 5 - -client.json().arrinsert("arr", Path.root_path(), 1, *[1, 2, 3]) - res = [0, 1, 2, 3, 4] - assert_resp_response(client, client.json().get("arr"), res, [[res]]) + assert client.json().get("arr") == [0, 1, 2, 3, 4] # test prepends client.json().set("val2", Path.root_path(), [5, 6, 7, 8, 9]) client.json().arrinsert("val2", Path.root_path(), 0, ["some", "thing"]) - res = [["some", "thing"], 5, 6, 7, 8, 9] - assert_resp_response(client, client.json().get("val2"), res, [[res]]) + assert client.json().get("val2") == [["some", "thing"], 5, 6, 7, 8, 9] @pytest.mark.redismod @@ -254,7 +247,7 @@ def test_arrpop(client): assert 3 == client.json().arrpop("arr", Path.root_path(), -1) assert 2 == client.json().arrpop("arr", Path.root_path()) assert 0 == client.json().arrpop("arr", Path.root_path(), 0) - assert_resp_response(client, client.json().get("arr"), [1], [[[1]]]) + assert [1] == client.json().get("arr") # test out of bounds client.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) @@ -269,7 +262,7 @@ def test_arrpop(client): def test_arrtrim(client): client.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) assert 3 == client.json().arrtrim("arr", Path.root_path(), 1, 3) - assert_resp_response(client, client.json().get("arr"), [1, 2, 3], [[[1, 2, 3]]]) + assert [1, 2, 3] == client.json().get("arr") # <0 test, should be 0 equivalent client.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) @@ -331,7 +324,7 @@ def test_json_commands_in_pipeline(client): p.set("foo", Path.root_path(), "bar") p.get("foo") p.delete("foo") - assert_resp_response(client, p.execute(), [True, "bar", 1], [True, [["bar"]], 1]) + assert p.execute() == [True, "bar", 1] assert client.keys() == [] assert client.get("foo") is None @@ -344,7 +337,7 @@ def test_json_commands_in_pipeline(client): p.jsonget("foo") p.exists("notarealkey") p.delete("foo") - assert_resp_response(client, p.execute(), [True, d, 0, 1], [True, [[d]], 0, 1]) + assert p.execute() == [True, d, 0, 1] assert client.keys() == [] assert client.get("foo") is None @@ -355,13 +348,13 @@ def test_json_delete_with_dollar(client): assert client.json().set("doc1", "$", doc1) assert client.json().delete("doc1", "$..a") == 2 res = [{"nested": {"b": 3}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res doc2 = {"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [True, "a", "b"]}} assert client.json().set("doc2", "$", doc2) assert client.json().delete("doc2", "$..a") == 1 res = [{"nested": {"b": [True, "a", "b"]}, "b": ["a", "b"]}] - assert_resp_response(client, client.json().get("doc2", "$"), res, [res]) + assert client.json().get("doc2", "$") == res doc3 = [ { @@ -392,7 +385,7 @@ def test_json_delete_with_dollar(client): } ] ] - assert_resp_response(client, client.json().get("doc3", "$"), doc3val, [doc3val]) + assert client.json().get("doc3", "$") == doc3val # Test default path assert client.json().delete("doc3") == 1 @@ -407,13 +400,13 @@ def test_json_forget_with_dollar(client): assert client.json().set("doc1", "$", doc1) assert client.json().forget("doc1", "$..a") == 2 res = [{"nested": {"b": 3}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res doc2 = {"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [True, "a", "b"]}} assert client.json().set("doc2", "$", doc2) assert client.json().forget("doc2", "$..a") == 1 res = [{"nested": {"b": [True, "a", "b"]}, "b": ["a", "b"]}] - assert_resp_response(client, client.json().get("doc2", "$"), res, [res]) + assert client.json().get("doc2", "$") == res doc3 = [ { @@ -444,7 +437,7 @@ def test_json_forget_with_dollar(client): } ] ] - assert_resp_response(client, client.json().get("doc3", "$"), doc3val, [doc3val]) + assert client.json().get("doc3", "$") == doc3val # Test default path assert client.json().forget("doc3") == 1 @@ -469,9 +462,9 @@ def test_json_mget_dollar(client): ) # Compare also to single JSON.GET res = [1, 3, None] - assert_resp_response(client, client.json().get("doc1", "$..a"), res, [res]) + assert client.json().get("doc1", "$..a") == res res = [4, 6, [None]] - assert_resp_response(client, client.json().get("doc2", "$..a"), res, [res]) + assert client.json().get("doc2", "$..a") == res # Test mget with single path assert client.json().mget(["doc1"], "$..a") == [[1, 3, None]] @@ -519,13 +512,15 @@ def test_numby_commands_dollar(client): # Test legacy NUMINCRBY client.json().set("doc1", "$", {"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}) - assert client.json().numincrby("doc1", ".b[0].a", 3) == 5 + assert_resp_response(client, client.json().numincrby("doc1", ".b[0].a", 3), 5, [5]) # Test legacy NUMMULTBY client.json().set("doc1", "$", {"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}) with pytest.deprecated_call(): - assert client.json().nummultby("doc1", ".b[0].a", 3) == 6 + assert_resp_response( + client, client.json().nummultby("doc1", ".b[0].a", 3), 6, [6] + ) @pytest.mark.redismod @@ -537,13 +532,13 @@ def test_strappend_dollar(client): assert client.json().strappend("doc1", "bar", "$..a") == [6, 8, None] res = [{"a": "foobar", "nested1": {"a": "hellobar"}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert_resp_response(client, client.json().get("doc1", "$"), res, res) # Test single assert client.json().strappend("doc1", "baz", "$.nested1.a") == [11] res = [{"a": "foobar", "nested1": {"a": "hellobarbaz"}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert_resp_response(client, client.json().get("doc1", "$"), res, res) # Test missing key with pytest.raises(exceptions.ResponseError): @@ -552,7 +547,7 @@ def test_strappend_dollar(client): # Test multi assert client.json().strappend("doc1", "bar", ".*.a") == 14 res = [{"a": "foobar", "nested1": {"a": "hellobarbazbar"}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert_resp_response(client, client.json().get("doc1", "$"), res, res) # Test missing path with pytest.raises(exceptions.ResponseError): @@ -600,7 +595,7 @@ def test_arrappend_dollar(client): "nested2": {"a": 31}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test single assert client.json().arrappend("doc1", "$.nested1.a", "baz") == [6] @@ -611,7 +606,7 @@ def test_arrappend_dollar(client): "nested2": {"a": 31}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -637,7 +632,7 @@ def test_arrappend_dollar(client): "nested2": {"a": 31}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test single assert client.json().arrappend("doc1", ".nested1.a", "baz") == 6 @@ -648,7 +643,7 @@ def test_arrappend_dollar(client): "nested2": {"a": 31}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -676,7 +671,7 @@ def test_arrinsert_dollar(client): "nested2": {"a": 31}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test single assert client.json().arrinsert("doc1", "$.nested1.a", -2, "baz") == [6] @@ -687,7 +682,7 @@ def test_arrinsert_dollar(client): "nested2": {"a": 31}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -759,7 +754,7 @@ def test_arrpop_dollar(client): assert client.json().arrpop("doc1", "$..a", 1) == ['"foo"', None, None] res = [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -778,7 +773,7 @@ def test_arrpop_dollar(client): # Test multi (all paths are updated, but return result of last path) assert client.json().arrpop("doc1", "..a", "1") == "null" res = [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # # Test missing key with pytest.raises(exceptions.ResponseError): @@ -799,16 +794,16 @@ def test_arrtrim_dollar(client): # Test multi assert client.json().arrtrim("doc1", "$..a", "1", -1) == [0, 2, None] res = [{"a": [], "nested1": {"a": [None, "world"]}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res assert client.json().arrtrim("doc1", "$..a", "1", "1") == [0, 1, None] res = [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test single assert client.json().arrtrim("doc1", "$.nested1.a", 1, 0) == [0] res = [{"a": [], "nested1": {"a": []}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -831,7 +826,7 @@ def test_arrtrim_dollar(client): # Test single assert client.json().arrtrim("doc1", ".nested1.a", "1", "1") == 1 res = [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -959,7 +954,7 @@ def test_clear_dollar(client): res = [ {"nested1": {"a": {}}, "a": [], "nested2": {"a": "claro"}, "nested3": {"a": {}}} ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test single client.json().set( @@ -981,11 +976,11 @@ def test_clear_dollar(client): "nested3": {"a": {"baz": 50}}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing path (defaults to root) assert client.json().clear("doc1") == 1 - assert_resp_response(client, client.json().get("doc1", "$"), [{}], [[{}]]) + assert client.json().get("doc1", "$") == [{}] # Test missing key with pytest.raises(exceptions.ResponseError): @@ -1014,7 +1009,7 @@ def test_toggle_dollar(client): "nested3": {"a": False}, } ] - assert_resp_response(client, client.json().get("doc1", "$"), res, [res]) + assert client.json().get("doc1", "$") == res # Test missing key with pytest.raises(exceptions.ResponseError): @@ -1294,12 +1289,10 @@ def test_arrindex_dollar(client): }, ) - assert_resp_response( - client, - client.json().get("store", "$.store.book[?(@.price<10)].size"), - [[10, 20, 30, 40], [5, 10, 20, 30]], - [[[10, 20, 30, 40], [5, 10, 20, 30]]], - ) + assert client.json().get("store", "$.store.book[?(@.price<10)].size") == [ + [10, 20, 30, 40], + [5, 10, 20, 30], + ] assert client.json().arrindex( "store", "$.store.book[?(@.price<10)].size", "20" @@ -1328,7 +1321,7 @@ def test_arrindex_dollar(client): "3", [], ] - assert_resp_response(client, client.json().get("test_num", "$..arr"), res, [res]) + assert client.json().get("test_num", "$..arr") == res assert client.json().arrindex("test_num", "$..arr", 3) == [3, 2, -1, None, -1] @@ -1361,7 +1354,7 @@ def test_arrindex_dollar(client): "3", [], ] - assert_resp_response(client, client.json().get("test_string", "$..arr"), res, [res]) + assert client.json().get("test_string", "$..arr") == res assert client.json().arrindex("test_string", "$..arr", "baz") == [ 3, @@ -1454,7 +1447,7 @@ def test_arrindex_dollar(client): None, [], ] - assert_resp_response(client, client.json().get("test_None", "$..arr"), res, [res]) + assert client.json().get("test_None", "$..arr") == res # Test with none-scalar value assert client.json().arrindex( @@ -1495,7 +1488,7 @@ def test_custom_decoder(client): cj = client.json(encoder=ujson, decoder=ujson) assert cj.set("foo", Path.root_path(), "bar") - assert_resp_response(client, cj.get("foo"), "bar", [["bar"]]) + assert cj.get("foo") == "bar" assert cj.get("baz") is None assert 1 == cj.delete("foo") assert client.exists("foo") == 0 @@ -1517,7 +1510,7 @@ def test_set_file(client): nojsonfile.write(b"Hello World") assert client.json().set_file("test", Path.root_path(), jsonfile.name) - assert_resp_response(client, client.json().get("test"), obj, [[obj]]) + assert client.json().get("test") == obj with pytest.raises(json.JSONDecodeError): client.json().set_file("test2", Path.root_path(), nojsonfile.name) @@ -1540,6 +1533,4 @@ def test_set_path(client): result = {jsonfile: True, nojsonfile: False} assert client.json().set_path(Path.root_path(), root) == result res = {"hello": "world"} - assert_resp_response( - client, client.json().get(jsonfile.rsplit(".")[0]), res, [[res]] - ) + assert client.json().get(jsonfile.rsplit(".")[0]) == res diff --git a/tests/test_timeseries.py b/tests/test_timeseries.py index 5647bd45c6..95402a1cee 100644 --- a/tests/test_timeseries.py +++ b/tests/test_timeseries.py @@ -1039,8 +1039,12 @@ def test_create_with_insertion_filters(client): assert 1021 == client.ts().add("time-series-1", 1021, 22.0) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0), (1010, 11.0), (1020, 11.5), (1021, 22.0)] - assert expected_points == data_points + assert_resp_response( + client, + data_points, + [(1000, 1.0), (1010, 11.0), (1020, 11.5), (1021, 22.0)], + [[1000, 1.0], [1010, 11.0], [1020, 11.5], [1021, 22.0]], + ) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -1056,8 +1060,12 @@ def test_create_with_insertion_filters_other_duplicate_policy(client): assert 1013 == client.ts().add("time-series-1", 1013, 10.0) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0), (1010, 11.0), (1013, 10)] - assert expected_points == data_points + assert_resp_response( + client, + data_points, + [(1000, 1.0), (1010, 11.0), (1013, 10)], + [[1000, 1.0], [1010, 11.0], [1013, 10]], + ) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -1076,8 +1084,12 @@ def test_alter_with_insertion_filters(client): assert 1013 == client.ts().add("time-series-1", 1015, 11.5) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0), (1010, 11.0), (1013, 10.0)] - assert expected_points == data_points + assert_resp_response( + client, + data_points, + [(1000, 1.0), (1010, 11.0), (1013, 10.0)], + [[1000, 1.0], [1010, 11.0], [1013, 10.0]], + ) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -1094,8 +1106,7 @@ def test_add_with_insertion_filters(client): assert 1000 == client.ts().add("time-series-1", 1004, 3.0) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0)] - assert expected_points == data_points + assert_resp_response(client, data_points, [(1000, 1.0)], [[1000, 1.0]]) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -1112,14 +1123,12 @@ def test_incrby_with_insertion_filters(client): assert 1000 == client.ts().incrby("time-series-1", 3.0, timestamp=1000) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 1.0)] - assert expected_points == data_points + assert_resp_response(client, data_points, [(1000, 1.0)], [[1000, 1.0]]) assert 1000 == client.ts().incrby("time-series-1", 10.1, timestamp=1000) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, 11.1)] - assert expected_points == data_points + assert_resp_response(client, data_points, [(1000, 11.1)], [[1000, 11.1]]) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -1136,14 +1145,12 @@ def test_decrby_with_insertion_filters(client): assert 1000 == client.ts().decrby("time-series-1", 3.0, timestamp=1000) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, -1.0)] - assert expected_points == data_points + assert_resp_response(client, data_points, [(1000, -1.0)], [[1000, -1.0]]) assert 1000 == client.ts().decrby("time-series-1", 10.1, timestamp=1000) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1000, -11.1)] - assert expected_points == data_points + assert_resp_response(client, data_points, [(1000, -11.1)], [[1000, -11.1]]) @skip_ifmodversion_lt("1.12.0", "timeseries") @@ -1165,5 +1172,9 @@ def test_madd_with_insertion_filters(client): ) data_points = client.ts().range("time-series-1", "-", "+") - expected_points = [(1010, 1.0), (1020, 2.0), (1021, 22.0)] - assert expected_points == data_points + assert_resp_response( + client, + data_points, + [(1010, 1.0), (1020, 2.0), (1021, 22.0)], + [[1010, 1.0], [1020, 2.0], [1021, 22.0]], + )