From ff7821dcb4867db3870477ae3cce90287c1f73c5 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Thu, 6 Jun 2024 15:43:30 +0300 Subject: [PATCH] Use standard Redis docker image in CI (#3246) Adapt the tests to use the standard Redis docker image where possible, instead of using the Redis Stack image in all places. This way we can run the CI against different versions of Redis and Redis Stack. Run the test cluster based on the default Redis docker image, i.e. without Stack support. This is needed in order to make the CI pass until Stack gets a new release. What is needed is to mark all Stack related tests accordingly, and then they don't get executed in the cluster tests (they are already filtered out in `invoke cluster-tests`). Take the opportunity to remove some empty tests and to fix the naming in two tests. --------- Co-authored-by: Gabriel Erzse --- docker-compose.yml | 39 +++++++------ dockers/Dockerfile.cluster | 4 +- dockers/cluster.redis.conf | 6 -- dockers/create_cluster.sh | 6 +- tasks.py | 2 +- tests/conftest.py | 17 +++++- tests/test_asyncio/test_bloom.py | 45 +++++++++------ tests/test_asyncio/test_graph.py | 26 +++++++++ tests/test_asyncio/test_json.py | 47 +++++++++++++++ tests/test_asyncio/test_search.py | 6 ++ tests/test_asyncio/test_timeseries.py | 59 ++++++++++++------- tests/test_bloom.py | 39 ++++++++++++- tests/test_cluster.py | 3 + tests/test_commands.py | 54 ++++++++--------- tests/test_graph.py | 26 ++++++++- tests/test_json.py | 83 ++++++++++++++++----------- tests/test_search.py | 4 +- tests/test_timeseries.py | 50 +++++++++++++++- 18 files changed, 384 insertions(+), 132 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 17d4b23977..09418ed094 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,12 +5,11 @@ version: "3.8" services: redis: - image: redis/redis-stack-server:edge + image: ${REDIS_IMAGE:-redis:latest} container_name: redis-standalone + command: redis-server --enable-debug-command yes ports: - 6379:6379 - environment: - - "REDIS_ARGS=--enable-debug-command yes --enable-module-command yes" profiles: - standalone - sentinel @@ -18,12 +17,11 @@ services: - all replica: - image: redis/redis-stack-server:edge + image: ${REDIS_IMAGE:-redis:latest} container_name: redis-replica depends_on: - redis - environment: - - "REDIS_ARGS=--replicaof redis 6379" + command: redis-server --replicaof redis 6379 ports: - 6380:6379 profiles: @@ -35,6 +33,8 @@ services: build: context: . dockerfile: dockers/Dockerfile.cluster + args: + REDIS_IMAGE: ${REDIS_IMAGE:-redis:latest} ports: - 16379:16379 - 16380:16380 @@ -63,13 +63,11 @@ services: - "./dockers/stunnel/keys:/etc/stunnel/keys:ro" sentinel: - image: redis/redis-stack-server:edge + image: ${REDIS_IMAGE:-redis:latest} container_name: redis-sentinel depends_on: - redis - environment: - - "REDIS_ARGS=--port 26379" - entrypoint: "/opt/redis-stack/bin/redis-sentinel /redis.conf --port 26379" + entrypoint: "/usr/local/bin/redis-sentinel /redis.conf --port 26379" ports: - 26379:26379 volumes: @@ -79,13 +77,11 @@ services: - all sentinel2: - image: redis/redis-stack-server:edge + image: ${REDIS_IMAGE:-redis:latest} container_name: redis-sentinel2 depends_on: - redis - environment: - - "REDIS_ARGS=--port 26380" - entrypoint: "/opt/redis-stack/bin/redis-sentinel /redis.conf --port 26380" + entrypoint: "/usr/local/bin/redis-sentinel /redis.conf --port 26380" ports: - 26380:26380 volumes: @@ -95,11 +91,11 @@ services: - all sentinel3: - image: redis/redis-stack-server:edge + image: ${REDIS_IMAGE:-redis:latest} container_name: redis-sentinel3 depends_on: - redis - entrypoint: "/opt/redis-stack/bin/redis-sentinel /redis.conf --port 26381" + entrypoint: "/usr/local/bin/redis-sentinel /redis.conf --port 26381" ports: - 26381:26381 volumes: @@ -107,3 +103,14 @@ services: profiles: - sentinel - all + + redis-stack: + image: redis/redis-stack-server:edge + container_name: redis-stack + ports: + - 6479:6379 + environment: + - "REDIS_ARGS=--enable-debug-command yes --enable-module-command yes" + profiles: + - standalone + - all diff --git a/dockers/Dockerfile.cluster b/dockers/Dockerfile.cluster index 3a0d73415e..4096009f9a 100644 --- a/dockers/Dockerfile.cluster +++ b/dockers/Dockerfile.cluster @@ -1,7 +1,7 @@ -FROM redis/redis-stack-server:edge as rss +ARG REDIS_IMAGE=redis:latest +FROM $REDIS_IMAGE COPY dockers/create_cluster.sh /create_cluster.sh -RUN ls -R /opt/redis-stack RUN chmod a+x /create_cluster.sh ENTRYPOINT [ "/create_cluster.sh"] diff --git a/dockers/cluster.redis.conf b/dockers/cluster.redis.conf index d4de46fbed..e9f7617d09 100644 --- a/dockers/cluster.redis.conf +++ b/dockers/cluster.redis.conf @@ -1,8 +1,2 @@ protected-mode no enable-debug-command yes -loadmodule /opt/redis-stack/lib/redisearch.so -loadmodule /opt/redis-stack/lib/redisgraph.so -loadmodule /opt/redis-stack/lib/redistimeseries.so -loadmodule /opt/redis-stack/lib/rejson.so -loadmodule /opt/redis-stack/lib/redisbloom.so -loadmodule /opt/redis-stack/lib/redisgears.so v8-plugin-path /opt/redis-stack/lib/libredisgears_v8_plugin.so diff --git a/dockers/create_cluster.sh b/dockers/create_cluster.sh index da9a0cb606..af41192585 100644 --- a/dockers/create_cluster.sh +++ b/dockers/create_cluster.sh @@ -31,7 +31,7 @@ dir /nodes/$PORT EOF set -x - /opt/redis-stack/bin/redis-server /nodes/$PORT/redis.conf + /usr/local/bin/redis-server /nodes/$PORT/redis.conf sleep 1 if [ $? -ne 0 ]; then echo "Redis failed to start, exiting." @@ -40,8 +40,8 @@ EOF echo 127.0.0.1:$PORT >> /nodes/nodemap done if [ -z "${REDIS_PASSWORD}" ]; then - echo yes | /opt/redis-stack/bin/redis-cli --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1 + echo yes | /usr/local/bin/redis-cli --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1 else - echo yes | opt/redis-stack/bin/redis-cli -a ${REDIS_PASSWORD} --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1 + echo yes | /usr/local/bin/redis-cli -a ${REDIS_PASSWORD} --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1 fi tail -f /redis.log diff --git a/tasks.py b/tasks.py index c60fa2791e..7f26081150 100644 --- a/tasks.py +++ b/tasks.py @@ -13,7 +13,7 @@ def devenv(c): """Brings up the test environment, by wrapping docker compose.""" clean(c) - cmd = "docker-compose --profile all up -d" + cmd = "docker-compose --profile all up -d --build" run(cmd) diff --git a/tests/conftest.py b/tests/conftest.py index e783b6e8f9..9263c4353d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -18,7 +18,7 @@ REDIS_INFO = {} default_redis_url = "redis://localhost:6379/0" default_protocol = "2" -default_redismod_url = "redis://localhost:6379" +default_redismod_url = "redis://localhost:6479" # default ssl client ignores verification for the purpose of testing default_redis_ssl_url = "rediss://localhost:6666" @@ -341,6 +341,21 @@ def r(request): yield client +@pytest.fixture() +def stack_url(request): + stack_url = request.config.getoption("--redis-url", default=default_redismod_url) + if stack_url == default_redis_url: + return default_redismod_url + else: + return stack_url + + +@pytest.fixture() +def stack_r(request, stack_url): + with _get_client(redis.Redis, request, from_url=stack_url) as client: + yield client + + @pytest.fixture() def decoded_r(request): with _get_client(redis.Redis, request, decode_responses=True) as client: diff --git a/tests/test_asyncio/test_bloom.py b/tests/test_asyncio/test_bloom.py index 278844416f..c63559a31c 100644 --- a/tests/test_asyncio/test_bloom.py +++ b/tests/test_asyncio/test_bloom.py @@ -1,6 +1,7 @@ from math import inf import pytest +import pytest_asyncio import redis.asyncio as redis from redis.exceptions import ModuleError, RedisError from redis.utils import HIREDIS_AVAILABLE @@ -11,10 +12,16 @@ ) +@pytest_asyncio.fixture() +async def decoded_r(create_redis, stack_url): + return await create_redis(decode_responses=True, url=stack_url) + + def intlist(obj): return [int(v) for v in obj] +@pytest.mark.redismod async def test_create(decoded_r: redis.Redis): """Test CREATE/RESERVE calls""" assert await decoded_r.bf().create("bloom", 0.01, 1000) @@ -30,10 +37,12 @@ async def test_create(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_create(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("tDigest", 100) +@pytest.mark.redismod async def test_bf_add(decoded_r: redis.Redis): assert await decoded_r.bf().create("bloom", 0.01, 1000) assert 1 == await decoded_r.bf().add("bloom", "foo") @@ -46,6 +55,7 @@ async def test_bf_add(decoded_r: redis.Redis): assert [1, 0] == intlist(await decoded_r.bf().mexists("bloom", "foo", "noexist")) +@pytest.mark.redismod async def test_bf_insert(decoded_r: redis.Redis): assert await decoded_r.bf().create("bloom", 0.01, 1000) assert [1] == intlist(await decoded_r.bf().insert("bloom", ["foo"])) @@ -76,6 +86,7 @@ async def test_bf_insert(decoded_r: redis.Redis): ) +@pytest.mark.redismod async def test_bf_scandump_and_loadchunk(decoded_r: redis.Redis): # Store a filter await decoded_r.bf().create("myBloom", "0.0001", "1000") @@ -127,6 +138,7 @@ async def do_verify(): await decoded_r.bf().create("myBloom", "0.0001", "10000000") +@pytest.mark.redismod async def test_bf_info(decoded_r: redis.Redis): expansion = 4 # Store a filter @@ -158,6 +170,7 @@ async def test_bf_info(decoded_r: redis.Redis): assert True +@pytest.mark.redismod async def test_bf_card(decoded_r: redis.Redis): # return 0 if the key does not exist assert await decoded_r.bf().card("not_exist") == 0 @@ -172,6 +185,7 @@ async def test_bf_card(decoded_r: redis.Redis): await decoded_r.bf().card("setKey") +@pytest.mark.redismod async def test_cf_add_and_insert(decoded_r: redis.Redis): assert await decoded_r.cf().create("cuckoo", 1000) assert await decoded_r.cf().add("cuckoo", "filter") @@ -197,6 +211,7 @@ async def test_cf_add_and_insert(decoded_r: redis.Redis): ) +@pytest.mark.redismod async def test_cf_exists_and_del(decoded_r: redis.Redis): assert await decoded_r.cf().create("cuckoo", 1000) assert await decoded_r.cf().add("cuckoo", "filter") @@ -208,6 +223,7 @@ async def test_cf_exists_and_del(decoded_r: redis.Redis): assert 0 == await decoded_r.cf().count("cuckoo", "filter") +@pytest.mark.redismod async def test_cms(decoded_r: redis.Redis): assert await decoded_r.cms().initbydim("dim", 1000, 5) assert await decoded_r.cms().initbyprob("prob", 0.01, 0.01) @@ -224,6 +240,7 @@ async def test_cms(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod async def test_cms_merge(decoded_r: redis.Redis): assert await decoded_r.cms().initbydim("A", 1000, 5) assert await decoded_r.cms().initbydim("B", 1000, 5) @@ -240,6 +257,7 @@ async def test_cms_merge(decoded_r: redis.Redis): assert [16, 15, 21] == await decoded_r.cms().query("C", "foo", "bar", "baz") +@pytest.mark.redismod async def test_topk(decoded_r: redis.Redis): # test list with empty buckets assert await decoded_r.topk().reserve("topk", 3, 50, 4, 0.9) @@ -320,6 +338,7 @@ async def test_topk(decoded_r: redis.Redis): assert 0.9 == round(float(info["decay"]), 1) +@pytest.mark.redismod async def test_topk_incrby(decoded_r: redis.Redis): await decoded_r.flushdb() assert await decoded_r.topk().reserve("topk", 3, 10, 3, 1) @@ -335,6 +354,7 @@ async def test_topk_incrby(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_reset(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("tDigest", 10) # reset on empty histogram @@ -351,6 +371,7 @@ async def test_tdigest_reset(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod async def test_tdigest_merge(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("to-tDigest", 10) assert await decoded_r.tdigest().create("from-tDigest", 10) @@ -378,6 +399,7 @@ async def test_tdigest_merge(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_min_and_max(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("tDigest", 100) # insert data-points into sketch @@ -388,6 +410,7 @@ async def test_tdigest_min_and_max(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod @skip_ifmodversion_lt("2.4.0", "bf") async def test_tdigest_quantile(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("tDigest", 500) @@ -416,6 +439,7 @@ async def test_tdigest_quantile(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_cdf(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("tDigest", 100) # insert data-points into sketch @@ -427,6 +451,7 @@ async def test_tdigest_cdf(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod @skip_ifmodversion_lt("2.4.0", "bf") async def test_tdigest_trimmed_mean(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("tDigest", 100) @@ -437,6 +462,7 @@ async def test_tdigest_trimmed_mean(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_rank(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("t-digest", 500) assert await decoded_r.tdigest().add("t-digest", list(range(0, 20))) @@ -447,6 +473,7 @@ async def test_tdigest_rank(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_revrank(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("t-digest", 500) assert await decoded_r.tdigest().add("t-digest", list(range(0, 20))) @@ -456,6 +483,7 @@ async def test_tdigest_revrank(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_byrank(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("t-digest", 500) assert await decoded_r.tdigest().add("t-digest", list(range(1, 11))) @@ -467,6 +495,7 @@ async def test_tdigest_byrank(decoded_r: redis.Redis): @pytest.mark.experimental +@pytest.mark.redismod async def test_tdigest_byrevrank(decoded_r: redis.Redis): assert await decoded_r.tdigest().create("t-digest", 500) assert await decoded_r.tdigest().add("t-digest", list(range(1, 11))) @@ -475,19 +504,3 @@ async def test_tdigest_byrevrank(decoded_r: redis.Redis): assert (await decoded_r.tdigest().byrevrank("t-digest", 100))[0] == -inf with pytest.raises(redis.ResponseError): (await decoded_r.tdigest().byrevrank("t-digest", -1))[0] - - -# # async def test_pipeline(decoded_r: redis.Redis): -# pipeline = await decoded_r.bf().pipeline() -# assert not await decoded_r.bf().execute_command("get pipeline") -# -# assert await decoded_r.bf().create("pipeline", 0.01, 1000) -# for i in range(100): -# pipeline.add("pipeline", i) -# for i in range(100): -# assert not (await decoded_r.bf().exists("pipeline", i)) -# -# pipeline.execute() -# -# for i in range(100): -# assert await decoded_r.bf().exists("pipeline", i) diff --git a/tests/test_asyncio/test_graph.py b/tests/test_asyncio/test_graph.py index 4caf79470e..9cd9149dcc 100644 --- a/tests/test_asyncio/test_graph.py +++ b/tests/test_asyncio/test_graph.py @@ -1,4 +1,5 @@ import pytest +import pytest_asyncio import redis.asyncio as redis from redis.commands.graph import Edge, Node, Path from redis.commands.graph.execution_plan import Operation @@ -6,12 +7,19 @@ from tests.conftest import skip_if_redis_enterprise +@pytest_asyncio.fixture() +async def decoded_r(create_redis, stack_url): + return await create_redis(decode_responses=True, url=stack_url) + + +@pytest.mark.redismod async def test_bulk(decoded_r): with pytest.raises(NotImplementedError): await decoded_r.graph().bulk() await decoded_r.graph().bulk(foo="bar!") +@pytest.mark.redismod async def test_graph_creation(decoded_r: redis.Redis): graph = decoded_r.graph() @@ -56,6 +64,7 @@ async def test_graph_creation(decoded_r: redis.Redis): await graph.delete() +@pytest.mark.redismod async def test_array_functions(decoded_r: redis.Redis): graph = decoded_r.graph() @@ -78,6 +87,7 @@ async def test_array_functions(decoded_r: redis.Redis): assert [a] == result.result_set[0][0] +@pytest.mark.redismod async def test_path(decoded_r: redis.Redis): node0 = Node(node_id=0, label="L1") node1 = Node(node_id=1, label="L1") @@ -97,6 +107,7 @@ async def test_path(decoded_r: redis.Redis): assert expected_results == result.result_set +@pytest.mark.redismod async def test_param(decoded_r: redis.Redis): params = [1, 2.3, "str", True, False, None, [0, 1, 2]] query = "RETURN $param" @@ -106,6 +117,7 @@ async def test_param(decoded_r: redis.Redis): assert expected_results == result.result_set +@pytest.mark.redismod async def test_map(decoded_r: redis.Redis): query = "RETURN {a:1, b:'str', c:NULL, d:[1,2,3], e:True, f:{x:1, y:2}}" @@ -122,6 +134,7 @@ async def test_map(decoded_r: redis.Redis): assert actual == expected +@pytest.mark.redismod async def test_point(decoded_r: redis.Redis): query = "RETURN point({latitude: 32.070794860, longitude: 34.820751118})" expected_lat = 32.070794860 @@ -138,6 +151,7 @@ async def test_point(decoded_r: redis.Redis): assert abs(actual["longitude"] - expected_lon) < 0.001 +@pytest.mark.redismod async def test_index_response(decoded_r: redis.Redis): result_set = await decoded_r.graph().query("CREATE INDEX ON :person(age)") assert 1 == result_set.indices_created @@ -152,6 +166,7 @@ async def test_index_response(decoded_r: redis.Redis): await decoded_r.graph().query("DROP INDEX ON :person(age)") +@pytest.mark.redismod async def test_stringify_query_result(decoded_r: redis.Redis): graph = decoded_r.graph() @@ -205,6 +220,7 @@ async def test_stringify_query_result(decoded_r: redis.Redis): await graph.delete() +@pytest.mark.redismod async def test_optional_match(decoded_r: redis.Redis): # Build a graph of form (a)-[R]->(b) node0 = Node(node_id=0, label="L1", properties={"value": "a"}) @@ -229,6 +245,7 @@ async def test_optional_match(decoded_r: redis.Redis): await graph.delete() +@pytest.mark.redismod async def test_cached_execution(decoded_r: redis.Redis): await decoded_r.graph().query("CREATE ()") @@ -248,6 +265,7 @@ async def test_cached_execution(decoded_r: redis.Redis): assert cached_result.cached_execution +@pytest.mark.redismod async def test_slowlog(decoded_r: redis.Redis): create_query = """CREATE (:Rider {name:'Valentino Rossi'})-[:rides]->(:Team {name:'Yamaha'}), @@ -261,6 +279,7 @@ async def test_slowlog(decoded_r: redis.Redis): @pytest.mark.xfail(strict=False) +@pytest.mark.redismod async def test_query_timeout(decoded_r: redis.Redis): # Build a sample graph with 1000 nodes. await decoded_r.graph().query("UNWIND range(0,1000) as val CREATE ({v: val})") @@ -274,6 +293,7 @@ async def test_query_timeout(decoded_r: redis.Redis): assert False is False +@pytest.mark.redismod async def test_read_only_query(decoded_r: redis.Redis): with pytest.raises(Exception): # Issue a write query, specifying read-only true, @@ -282,6 +302,7 @@ async def test_read_only_query(decoded_r: redis.Redis): assert False is False +@pytest.mark.redismod async def test_profile(decoded_r: redis.Redis): q = """UNWIND range(1, 3) AS x CREATE (p:Person {v:x})""" profile = (await decoded_r.graph().profile(q)).result_set @@ -297,6 +318,7 @@ async def test_profile(decoded_r: redis.Redis): @skip_if_redis_enterprise() +@pytest.mark.redismod async def test_config(decoded_r: redis.Redis): config_name = "RESULTSET_SIZE" config_value = 3 @@ -328,6 +350,7 @@ async def test_config(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod async def test_list_keys(decoded_r: redis.Redis): result = await decoded_r.graph().list_keys() assert result == [] @@ -350,6 +373,7 @@ async def test_list_keys(decoded_r: redis.Redis): assert result == [] +@pytest.mark.redismod async def test_multi_label(decoded_r: redis.Redis): redis_graph = decoded_r.graph("g") @@ -375,6 +399,7 @@ async def test_multi_label(decoded_r: redis.Redis): assert True +@pytest.mark.redismod async def test_execution_plan(decoded_r: redis.Redis): redis_graph = decoded_r.graph("execution_plan") create_query = """CREATE @@ -393,6 +418,7 @@ async def test_execution_plan(decoded_r: redis.Redis): await redis_graph.delete() +@pytest.mark.redismod async def test_explain(decoded_r: redis.Redis): redis_graph = decoded_r.graph("execution_plan") # graph creation / population diff --git a/tests/test_asyncio/test_json.py b/tests/test_asyncio/test_json.py index 920ec71dce..c713f1aca2 100644 --- a/tests/test_asyncio/test_json.py +++ b/tests/test_asyncio/test_json.py @@ -1,10 +1,17 @@ import pytest +import pytest_asyncio import redis.asyncio as redis from redis import exceptions from redis.commands.json.path import Path from tests.conftest import assert_resp_response, skip_ifmodversion_lt +@pytest_asyncio.fixture() +async def decoded_r(create_redis, stack_url): + return await create_redis(decode_responses=True, url=stack_url) + + +@pytest.mark.redismod async def test_json_setbinarykey(decoded_r: redis.Redis): d = {"hello": "world", b"some": "value"} with pytest.raises(TypeError): @@ -12,6 +19,7 @@ async def test_json_setbinarykey(decoded_r: redis.Redis): assert await decoded_r.json().set("somekey", Path.root_path(), d, decode_keys=True) +@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"]]) @@ -21,11 +29,13 @@ async def test_json_setgetdeleteforget(decoded_r: redis.Redis): assert await decoded_r.exists("foo") == 0 +@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"]]) +@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"]]) @@ -34,6 +44,7 @@ async def test_json_get_jset(decoded_r: redis.Redis): assert await decoded_r.exists("foo") == 0 +@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" @@ -44,6 +55,7 @@ async def test_nonascii_setgetdelete(decoded_r: redis.Redis): assert await decoded_r.exists("notascii") == 0 +@pytest.mark.redismod @skip_ifmodversion_lt("2.6.0", "ReJSON") async def test_json_merge(decoded_r: redis.Redis): # Test with root path $ @@ -78,6 +90,7 @@ async def test_json_merge(decoded_r: redis.Redis): } +@pytest.mark.redismod async def test_jsonsetexistentialmodifiersshouldsucceed(decoded_r: redis.Redis): obj = {"foo": "bar"} assert await decoded_r.json().set("obj", Path.root_path(), obj) @@ -95,6 +108,7 @@ async def test_jsonsetexistentialmodifiersshouldsucceed(decoded_r: redis.Redis): await decoded_r.json().set("obj", Path("foo"), "baz", nx=True, xx=True) +@pytest.mark.redismod async def test_mgetshouldsucceed(decoded_r: redis.Redis): await decoded_r.json().set("1", Path.root_path(), 1) await decoded_r.json().set("2", Path.root_path(), 2) @@ -104,6 +118,7 @@ async def test_mgetshouldsucceed(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("2.6.0", "ReJSON") async def test_mset(decoded_r: redis.Redis): await decoded_r.json().mset( @@ -114,6 +129,7 @@ async def test_mset(decoded_r: redis.Redis): assert await decoded_r.json().mget(["1", "2"], Path.root_path()) == [1, 2] +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "ReJSON") # todo: update after the release async def test_clear(decoded_r: redis.Redis): await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) @@ -121,6 +137,7 @@ async def test_clear(decoded_r: redis.Redis): assert_resp_response(decoded_r, await decoded_r.json().get("arr"), [], [[[]]]) +@pytest.mark.redismod async def test_type(decoded_r: redis.Redis): await decoded_r.json().set("1", Path.root_path(), 1) assert_resp_response( @@ -134,6 +151,7 @@ async def test_type(decoded_r: redis.Redis): ) +@pytest.mark.redismod async def test_numincrby(decoded_r): await decoded_r.json().set("num", Path.root_path(), 1) assert_resp_response( @@ -145,6 +163,7 @@ async def test_numincrby(decoded_r): assert_resp_response(decoded_r, res, 1.25, [1.25]) +@pytest.mark.redismod async def test_nummultby(decoded_r: redis.Redis): await decoded_r.json().set("num", Path.root_path(), 1) @@ -157,6 +176,7 @@ async def test_nummultby(decoded_r: redis.Redis): assert_resp_response(decoded_r, res, 2.5, [2.5]) +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "ReJSON") # todo: update after the release async def test_toggle(decoded_r: redis.Redis): await decoded_r.json().set("bool", Path.root_path(), False) @@ -168,6 +188,7 @@ async def test_toggle(decoded_r: redis.Redis): await decoded_r.json().toggle("num", Path.root_path()) +@pytest.mark.redismod 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") @@ -175,6 +196,7 @@ async def test_strappend(decoded_r: redis.Redis): assert_resp_response(decoded_r, res, "foobar", [["foobar"]]) +@pytest.mark.redismod async def test_strlen(decoded_r: redis.Redis): await decoded_r.json().set("str", Path.root_path(), "foo") assert 3 == await decoded_r.json().strlen("str", Path.root_path()) @@ -183,6 +205,7 @@ async def test_strlen(decoded_r: redis.Redis): assert 6 == await decoded_r.json().strlen("str") +@pytest.mark.redismod async def test_arrappend(decoded_r: redis.Redis): await decoded_r.json().set("arr", Path.root_path(), [1]) assert 2 == await decoded_r.json().arrappend("arr", Path.root_path(), 2) @@ -190,6 +213,7 @@ async def test_arrappend(decoded_r: redis.Redis): assert 7 == await decoded_r.json().arrappend("arr", Path.root_path(), *[5, 6, 7]) +@pytest.mark.redismod async def test_arrindex(decoded_r: redis.Redis): r_path = Path.root_path() await decoded_r.json().set("arr", r_path, [0, 1, 2, 3, 4]) @@ -202,6 +226,7 @@ async def test_arrindex(decoded_r: redis.Redis): assert -1 == await decoded_r.json().arrindex("arr", r_path, 4, start=1, stop=3) +@pytest.mark.redismod 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]) @@ -215,6 +240,7 @@ async def test_arrinsert(decoded_r: redis.Redis): assert_resp_response(decoded_r, await decoded_r.json().get("val2"), res, [[res]]) +@pytest.mark.redismod async def test_arrlen(decoded_r: redis.Redis): await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) assert 5 == await decoded_r.json().arrlen("arr", Path.root_path()) @@ -222,6 +248,7 @@ async def test_arrlen(decoded_r: redis.Redis): assert await decoded_r.json().arrlen("fakekey") is None +@pytest.mark.redismod async def test_arrpop(decoded_r: redis.Redis): await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) assert 4 == await decoded_r.json().arrpop("arr", Path.root_path(), 4) @@ -239,6 +266,7 @@ async def test_arrpop(decoded_r: redis.Redis): assert await decoded_r.json().arrpop("arr") is None +@pytest.mark.redismod 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) @@ -262,6 +290,7 @@ async def test_arrtrim(decoded_r: redis.Redis): assert 0 == await decoded_r.json().arrtrim("arr", Path.root_path(), 9, 11) +@pytest.mark.redismod async def test_resp(decoded_r: redis.Redis): obj = {"foo": "bar", "baz": 1, "qaz": True} await decoded_r.json().set("obj", Path.root_path(), obj) @@ -271,6 +300,7 @@ async def test_resp(decoded_r: redis.Redis): assert isinstance(await decoded_r.json().resp("obj"), list) +@pytest.mark.redismod async def test_objkeys(decoded_r: redis.Redis): obj = {"foo": "bar", "baz": "qaz"} await decoded_r.json().set("obj", Path.root_path(), obj) @@ -287,6 +317,7 @@ async def test_objkeys(decoded_r: redis.Redis): assert await decoded_r.json().objkeys("fakekey") is None +@pytest.mark.redismod async def test_objlen(decoded_r: redis.Redis): obj = {"foo": "bar", "baz": "qaz"} await decoded_r.json().set("obj", Path.root_path(), obj) @@ -320,6 +351,7 @@ async def test_objlen(decoded_r: redis.Redis): # assert await decoded_r.get("foo") is None +@pytest.mark.redismod 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) @@ -373,6 +405,7 @@ async def test_json_delete_with_dollar(decoded_r: redis.Redis): await decoded_r.json().delete("not_a_document", "..a") +@pytest.mark.redismod 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) @@ -426,6 +459,7 @@ async def test_json_forget_with_dollar(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod async def test_json_mget_dollar(decoded_r: redis.Redis): # Test mget with multi paths await decoded_r.json().set( @@ -461,6 +495,7 @@ async def test_json_mget_dollar(decoded_r: redis.Redis): assert res == [None, None] +@pytest.mark.redismod async def test_numby_commands_dollar(decoded_r: redis.Redis): # Test NUMINCRBY await decoded_r.json().set( @@ -515,6 +550,7 @@ async def test_numby_commands_dollar(decoded_r: redis.Redis): await decoded_r.json().nummultby("doc1", ".b[0].a", 3) == 6 +@pytest.mark.redismod async def test_strappend_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", "$", {"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}} @@ -545,6 +581,7 @@ async def test_strappend_dollar(decoded_r: redis.Redis): await decoded_r.json().strappend("doc1", "piu") +@pytest.mark.redismod async def test_strlen_dollar(decoded_r: redis.Redis): # Test multi await decoded_r.json().set( @@ -565,6 +602,7 @@ async def test_strlen_dollar(decoded_r: redis.Redis): await decoded_r.json().strlen("non_existing_doc", "$..a") +@pytest.mark.redismod async def test_arrappend_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -638,6 +676,7 @@ async def test_arrappend_dollar(decoded_r: redis.Redis): await decoded_r.json().arrappend("non_existing_doc", "$..a") +@pytest.mark.redismod async def test_arrinsert_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -676,6 +715,7 @@ async def test_arrinsert_dollar(decoded_r: redis.Redis): await decoded_r.json().arrappend("non_existing_doc", "$..a") +@pytest.mark.redismod async def test_arrlen_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -721,6 +761,7 @@ async def test_arrlen_dollar(decoded_r: redis.Redis): assert await decoded_r.json().arrlen("non_existing_doc", "..a") is None +@pytest.mark.redismod async def test_arrpop_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -762,6 +803,7 @@ async def test_arrpop_dollar(decoded_r: redis.Redis): await decoded_r.json().arrpop("non_existing_doc", "..a") +@pytest.mark.redismod async def test_arrtrim_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -813,6 +855,7 @@ async def test_arrtrim_dollar(decoded_r: redis.Redis): await decoded_r.json().arrtrim("non_existing_doc", "..a", 1, 1) +@pytest.mark.redismod async def test_objkeys_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -842,6 +885,7 @@ async def test_objkeys_dollar(decoded_r: redis.Redis): assert await decoded_r.json().objkeys("doc1", "$..nowhere") == [] +@pytest.mark.redismod async def test_objlen_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -896,6 +940,7 @@ def load_types_data(nested_key_name): return jdata, types +@pytest.mark.redismod async def test_type_dollar(decoded_r: redis.Redis): jdata, jtypes = load_types_data("a") await decoded_r.json().set("doc1", "$", jdata) @@ -914,6 +959,7 @@ async def test_type_dollar(decoded_r: redis.Redis): ) +@pytest.mark.redismod async def test_clear_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", @@ -967,6 +1013,7 @@ async def test_clear_dollar(decoded_r: redis.Redis): await decoded_r.json().clear("non_existing_doc", "$..a") +@pytest.mark.redismod async def test_toggle_dollar(decoded_r: redis.Redis): await decoded_r.json().set( "doc1", diff --git a/tests/test_asyncio/test_search.py b/tests/test_asyncio/test_search.py index 8d42d08b66..4cc00c8e5f 100644 --- a/tests/test_asyncio/test_search.py +++ b/tests/test_asyncio/test_search.py @@ -5,6 +5,7 @@ from io import TextIOWrapper import pytest +import pytest_asyncio import redis.asyncio as redis import redis.commands.search import redis.commands.search.aggregation as aggregations @@ -31,6 +32,11 @@ ) +@pytest_asyncio.fixture() +async def decoded_r(create_redis, stack_url): + return await create_redis(decode_responses=True, url=stack_url) + + async def waitForIndex(env, idx, timeout=None): delay = 0.1 while True: diff --git a/tests/test_asyncio/test_timeseries.py b/tests/test_asyncio/test_timeseries.py index b44219707e..0c78ce0941 100644 --- a/tests/test_asyncio/test_timeseries.py +++ b/tests/test_asyncio/test_timeseries.py @@ -2,6 +2,7 @@ from time import sleep import pytest +import pytest_asyncio import redis.asyncio as redis from tests.conftest import ( assert_resp_response, @@ -10,6 +11,12 @@ ) +@pytest_asyncio.fixture() +async def decoded_r(create_redis, stack_url): + return await create_redis(decode_responses=True, url=stack_url) + + +@pytest.mark.redismod async def test_create(decoded_r: redis.Redis): assert await decoded_r.ts().create(1) assert await decoded_r.ts().create(2, retention_msecs=5) @@ -27,6 +34,7 @@ async def test_create(decoded_r: redis.Redis): assert_resp_response(decoded_r, 128, info.get("chunk_size"), info.get("chunkSize")) +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") async def test_create_duplicate_policy(decoded_r: redis.Redis): # Test for duplicate policy @@ -42,6 +50,7 @@ async def test_create_duplicate_policy(decoded_r: redis.Redis): ) +@pytest.mark.redismod async def test_alter(decoded_r: redis.Redis): assert await decoded_r.ts().create(1) res = await decoded_r.ts().info(1) @@ -64,6 +73,7 @@ async def test_alter(decoded_r: redis.Redis): ) +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") async def test_alter_diplicate_policy(decoded_r: redis.Redis): assert await decoded_r.ts().create(1) @@ -78,6 +88,7 @@ async def test_alter_diplicate_policy(decoded_r: redis.Redis): ) +@pytest.mark.redismod async def test_add(decoded_r: redis.Redis): assert 1 == await decoded_r.ts().add(1, 1, 1) assert 2 == await decoded_r.ts().add(2, 2, 3, retention_msecs=10) @@ -100,6 +111,7 @@ async def test_add(decoded_r: redis.Redis): assert_resp_response(decoded_r, 128, info.get("chunk_size"), info.get("chunkSize")) +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") async def test_add_duplicate_policy(r: redis.Redis): # Test for duplicate policy BLOCK @@ -140,6 +152,7 @@ async def test_add_duplicate_policy(r: redis.Redis): assert 5.0 == res[1] +@pytest.mark.redismod async def test_madd(decoded_r: redis.Redis): await decoded_r.ts().create("a") assert [1, 2, 3] == await decoded_r.ts().madd( @@ -147,6 +160,7 @@ async def test_madd(decoded_r: redis.Redis): ) +@pytest.mark.redismod async def test_incrby_decrby(decoded_r: redis.Redis): for _ in range(100): assert await decoded_r.ts().incrby(1, 1) @@ -175,6 +189,7 @@ async def test_incrby_decrby(decoded_r: redis.Redis): assert_resp_response(decoded_r, 128, info.get("chunk_size"), info.get("chunkSize")) +@pytest.mark.redismod async def test_create_and_delete_rule(decoded_r: redis.Redis): # test rule creation time = 100 @@ -198,6 +213,7 @@ async def test_create_and_delete_rule(decoded_r: redis.Redis): assert not info["rules"] +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") async def test_del_range(decoded_r: redis.Redis): try: @@ -214,20 +230,24 @@ async def test_del_range(decoded_r: redis.Redis): ) -async def test_range(r: redis.Redis): +@pytest.mark.redismod +async def test_range(decoded_r: redis.Redis): for i in range(100): - await r.ts().add(1, i, i % 7) - assert 100 == len(await r.ts().range(1, 0, 200)) + await decoded_r.ts().add(1, i, i % 7) + assert 100 == len(await decoded_r.ts().range(1, 0, 200)) for i in range(100): - await r.ts().add(1, i + 200, i % 7) - assert 200 == len(await r.ts().range(1, 0, 500)) + await decoded_r.ts().add(1, i + 200, i % 7) + assert 200 == len(await decoded_r.ts().range(1, 0, 500)) # last sample isn't returned assert 20 == len( - await r.ts().range(1, 0, 500, aggregation_type="avg", bucket_size_msec=10) + await decoded_r.ts().range( + 1, 0, 500, aggregation_type="avg", bucket_size_msec=10 + ) ) - assert 10 == len(await r.ts().range(1, 0, 500, count=10)) + assert 10 == len(await decoded_r.ts().range(1, 0, 500, count=10)) +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") async def test_range_advanced(decoded_r: redis.Redis): for i in range(100): @@ -258,6 +278,7 @@ async def test_range_advanced(decoded_r: redis.Redis): assert_resp_response(decoded_r, res, [(0, 2.55), (10, 3.0)], [[0, 2.55], [10, 3.0]]) +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") async def test_rev_range(decoded_r: redis.Redis): for i in range(100): @@ -302,6 +323,7 @@ async def test_rev_range(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod async def test_multi_range(decoded_r: redis.Redis): await decoded_r.ts().create(1, labels={"Test": "This", "team": "ny"}) await decoded_r.ts().create( @@ -356,6 +378,7 @@ async def test_multi_range(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") async def test_multi_range_advanced(decoded_r: redis.Redis): await decoded_r.ts().create(1, labels={"Test": "This", "team": "ny"}) @@ -473,6 +496,7 @@ async def test_multi_range_advanced(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") async def test_multi_reverse_range(decoded_r: redis.Redis): await decoded_r.ts().create(1, labels={"Test": "This", "team": "ny"}) @@ -635,6 +659,7 @@ async def test_multi_reverse_range(decoded_r: redis.Redis): assert [[1, 10.0], [0, 1.0]] == res["1"][2] +@pytest.mark.redismod async def test_get(decoded_r: redis.Redis): name = "test" await decoded_r.ts().create(name) @@ -646,6 +671,7 @@ async def test_get(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod async def test_mget(decoded_r: redis.Redis): await decoded_r.ts().create(1, labels={"Test": "This"}) await decoded_r.ts().create(2, labels={"Test": "This", "Taste": "That"}) @@ -680,6 +706,7 @@ async def test_mget(decoded_r: redis.Redis): assert {"Taste": "That", "Test": "This"} == res["2"][0] +@pytest.mark.redismod async def test_info(decoded_r: redis.Redis): await decoded_r.ts().create( 1, retention_msecs=5, labels={"currentLabel": "currentData"} @@ -691,8 +718,9 @@ async def test_info(decoded_r: redis.Redis): assert info["labels"]["currentLabel"] == "currentData" +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") -async def testInfoDuplicatePolicy(decoded_r: redis.Redis): +async def test_info_duplicate_policy(decoded_r: redis.Redis): await decoded_r.ts().create( 1, retention_msecs=5, labels={"currentLabel": "currentData"} ) @@ -709,6 +737,7 @@ async def testInfoDuplicatePolicy(decoded_r: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod async def test_query_index(decoded_r: redis.Redis): await decoded_r.ts().create(1, labels={"Test": "This"}) await decoded_r.ts().create(2, labels={"Test": "This", "Taste": "That"}) @@ -719,19 +748,7 @@ async def test_query_index(decoded_r: redis.Redis): ) -# # async def test_pipeline(r: redis.Redis): -# pipeline = await r.ts().pipeline() -# pipeline.create("with_pipeline") -# for i in range(100): -# pipeline.add("with_pipeline", i, 1.1 * i) -# pipeline.execute() - -# info = await r.ts().info("with_pipeline") -# assert info.lastTimeStamp == 99 -# assert info.total_samples == 100 -# assert await r.ts().get("with_pipeline")[1] == 99 * 1.1 - - +@pytest.mark.redismod async def test_uncompressed(decoded_r: redis.Redis): await decoded_r.ts().create("compressed") await decoded_r.ts().create("uncompressed", uncompressed=True) diff --git a/tests/test_bloom.py b/tests/test_bloom.py index 464a946f54..d1a0484225 100644 --- a/tests/test_bloom.py +++ b/tests/test_bloom.py @@ -5,7 +5,20 @@ from redis.exceptions import ModuleError, RedisError from redis.utils import HIREDIS_AVAILABLE -from .conftest import assert_resp_response, is_resp2_connection, skip_ifmodversion_lt +from .conftest import ( + _get_client, + assert_resp_response, + is_resp2_connection, + skip_ifmodversion_lt, +) + + +@pytest.fixture() +def decoded_r(request, stack_url): + with _get_client( + redis.Redis, request, decode_responses=True, from_url=stack_url + ) as client: + yield client def intlist(obj): @@ -24,6 +37,7 @@ def client(decoded_r): return decoded_r +@pytest.mark.redismod def test_create(client): """Test CREATE/RESERVE calls""" assert client.bf().create("bloom", 0.01, 1000) @@ -38,6 +52,7 @@ def test_create(client): assert client.topk().reserve("topk", 5, 100, 5, 0.9) +@pytest.mark.redismod def test_bf_reserve(client): """Testing BF.RESERVE""" assert client.bf().reserve("bloom", 0.01, 1000) @@ -53,10 +68,12 @@ def test_bf_reserve(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_create(client): assert client.tdigest().create("tDigest", 100) +@pytest.mark.redismod def test_bf_add(client): assert client.bf().create("bloom", 0.01, 1000) assert 1 == client.bf().add("bloom", "foo") @@ -69,6 +86,7 @@ def test_bf_add(client): assert [1, 0] == intlist(client.bf().mexists("bloom", "foo", "noexist")) +@pytest.mark.redismod def test_bf_insert(client): assert client.bf().create("bloom", 0.01, 1000) assert [1] == intlist(client.bf().insert("bloom", ["foo"])) @@ -99,6 +117,7 @@ def test_bf_insert(client): ) +@pytest.mark.redismod def test_bf_scandump_and_loadchunk(client): # Store a filter client.bf().create("myBloom", "0.0001", "1000") @@ -150,6 +169,7 @@ def do_verify(): client.bf().create("myBloom", "0.0001", "10000000") +@pytest.mark.redismod def test_bf_info(client): expansion = 4 # Store a filter @@ -181,6 +201,7 @@ def test_bf_info(client): assert True +@pytest.mark.redismod def test_bf_card(client): # return 0 if the key does not exist assert client.bf().card("not_exist") == 0 @@ -195,6 +216,7 @@ def test_bf_card(client): client.bf().card("setKey") +@pytest.mark.redismod def test_cf_add_and_insert(client): assert client.cf().create("cuckoo", 1000) assert client.cf().add("cuckoo", "filter") @@ -220,6 +242,7 @@ def test_cf_add_and_insert(client): ) +@pytest.mark.redismod def test_cf_exists_and_del(client): assert client.cf().create("cuckoo", 1000) assert client.cf().add("cuckoo", "filter") @@ -232,6 +255,7 @@ def test_cf_exists_and_del(client): assert 0 == client.cf().count("cuckoo", "filter") +@pytest.mark.redismod def test_cms(client): assert client.cms().initbydim("dim", 1000, 5) assert client.cms().initbyprob("prob", 0.01, 0.01) @@ -248,6 +272,7 @@ def test_cms(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod def test_cms_merge(client): assert client.cms().initbydim("A", 1000, 5) assert client.cms().initbydim("B", 1000, 5) @@ -264,6 +289,7 @@ def test_cms_merge(client): assert [16, 15, 21] == client.cms().query("C", "foo", "bar", "baz") +@pytest.mark.redismod def test_topk(client): # test list with empty buckets assert client.topk().reserve("topk", 3, 50, 4, 0.9) @@ -343,6 +369,7 @@ def test_topk(client): assert 0.9 == round(float(info["decay"]), 1) +@pytest.mark.redismod def test_topk_incrby(client): client.flushdb() assert client.topk().reserve("topk", 3, 10, 3, 1) @@ -357,6 +384,7 @@ def test_topk_incrby(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_reset(client): assert client.tdigest().create("tDigest", 10) # reset on empty histogram @@ -373,6 +401,7 @@ def test_tdigest_reset(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod def test_tdigest_merge(client): assert client.tdigest().create("to-tDigest", 10) assert client.tdigest().create("from-tDigest", 10) @@ -400,6 +429,7 @@ def test_tdigest_merge(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_min_and_max(client): assert client.tdigest().create("tDigest", 100) # insert data-points into sketch @@ -410,6 +440,7 @@ def test_tdigest_min_and_max(client): @pytest.mark.experimental +@pytest.mark.redismod @skip_ifmodversion_lt("2.4.0", "bf") def test_tdigest_quantile(client): assert client.tdigest().create("tDigest", 500) @@ -431,6 +462,7 @@ def test_tdigest_quantile(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_cdf(client): assert client.tdigest().create("tDigest", 100) # insert data-points into sketch @@ -442,6 +474,7 @@ def test_tdigest_cdf(client): @pytest.mark.experimental +@pytest.mark.redismod @skip_ifmodversion_lt("2.4.0", "bf") def test_tdigest_trimmed_mean(client): assert client.tdigest().create("tDigest", 100) @@ -452,6 +485,7 @@ def test_tdigest_trimmed_mean(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_rank(client): assert client.tdigest().create("t-digest", 500) assert client.tdigest().add("t-digest", list(range(0, 20))) @@ -462,6 +496,7 @@ def test_tdigest_rank(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_revrank(client): assert client.tdigest().create("t-digest", 500) assert client.tdigest().add("t-digest", list(range(0, 20))) @@ -471,6 +506,7 @@ def test_tdigest_revrank(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_byrank(client): assert client.tdigest().create("t-digest", 500) assert client.tdigest().add("t-digest", list(range(1, 11))) @@ -482,6 +518,7 @@ def test_tdigest_byrank(client): @pytest.mark.experimental +@pytest.mark.redismod def test_tdigest_byrevrank(client): assert client.tdigest().create("t-digest", 500) assert client.tdigest().add("t-digest", list(range(1, 11))) diff --git a/tests/test_cluster.py b/tests/test_cluster.py index 1f505b816d..d41ebcd506 100644 --- a/tests/test_cluster.py +++ b/tests/test_cluster.py @@ -2450,6 +2450,7 @@ def try_delete_libs(self, r, *lib_names): except Exception: pass + @pytest.mark.redismod @skip_if_server_version_lt("7.1.140") def test_tfunction_load_delete(self, r): r.gears_refresh_cluster() @@ -2458,6 +2459,7 @@ def test_tfunction_load_delete(self, r): assert r.tfunction_load(lib_code) assert r.tfunction_delete("lib1") + @pytest.mark.redismod @skip_if_server_version_lt("7.1.140") def test_tfunction_list(self, r): r.gears_refresh_cluster() @@ -2481,6 +2483,7 @@ def test_tfunction_list(self, r): assert r.tfunction_delete("lib2") assert r.tfunction_delete("lib3") + @pytest.mark.redismod @skip_if_server_version_lt("7.1.140") def test_tfcall(self, r): r.gears_refresh_cluster() diff --git a/tests/test_commands.py b/tests/test_commands.py index 54df183fc6..8fbec5fb7e 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1818,44 +1818,44 @@ def try_delete_libs(self, r, *lib_names): @pytest.mark.onlynoncluster @skip_if_server_version_lt("7.1.140") - def test_tfunction_load_delete(self, r): - self.try_delete_libs(r, "lib1") + def test_tfunction_load_delete(self, stack_r): + self.try_delete_libs(stack_r, "lib1") lib_code = self.generate_lib_code("lib1") - assert r.tfunction_load(lib_code) - assert r.tfunction_delete("lib1") + assert stack_r.tfunction_load(lib_code) + assert stack_r.tfunction_delete("lib1") @pytest.mark.onlynoncluster @skip_if_server_version_lt("7.1.140") - def test_tfunction_list(self, r): - self.try_delete_libs(r, "lib1", "lib2", "lib3") - assert r.tfunction_load(self.generate_lib_code("lib1")) - assert r.tfunction_load(self.generate_lib_code("lib2")) - assert r.tfunction_load(self.generate_lib_code("lib3")) + def test_tfunction_list(self, stack_r): + self.try_delete_libs(stack_r, "lib1", "lib2", "lib3") + assert stack_r.tfunction_load(self.generate_lib_code("lib1")) + assert stack_r.tfunction_load(self.generate_lib_code("lib2")) + assert stack_r.tfunction_load(self.generate_lib_code("lib3")) # test error thrown when verbose > 4 with pytest.raises(redis.exceptions.DataError): - assert r.tfunction_list(verbose=8) + assert stack_r.tfunction_list(verbose=8) - functions = r.tfunction_list(verbose=1) + functions = stack_r.tfunction_list(verbose=1) assert len(functions) == 3 expected_names = [b"lib1", b"lib2", b"lib3"] actual_names = [functions[0][13], functions[1][13], functions[2][13]] assert sorted(expected_names) == sorted(actual_names) - assert r.tfunction_delete("lib1") - assert r.tfunction_delete("lib2") - assert r.tfunction_delete("lib3") + assert stack_r.tfunction_delete("lib1") + assert stack_r.tfunction_delete("lib2") + assert stack_r.tfunction_delete("lib3") @pytest.mark.onlynoncluster @skip_if_server_version_lt("7.1.140") - def test_tfcall(self, r): - self.try_delete_libs(r, "lib1") - assert r.tfunction_load(self.generate_lib_code("lib1")) - assert r.tfcall("lib1", "foo") == b"bar" - assert r.tfcall_async("lib1", "foo") == b"bar" + def test_tfcall(self, stack_r): + self.try_delete_libs(stack_r, "lib1") + assert stack_r.tfunction_load(self.generate_lib_code("lib1")) + assert stack_r.tfcall("lib1", "foo") == b"bar" + assert stack_r.tfcall_async("lib1", "foo") == b"bar" - assert r.tfunction_delete("lib1") + assert stack_r.tfunction_delete("lib1") def test_ttl(self, r): r["a"] = "1" @@ -5022,25 +5022,27 @@ def test_command_getkeysandflags(self, r: redis.Redis): @pytest.mark.onlynoncluster @skip_if_server_version_lt("4.0.0") @skip_if_redis_enterprise() - def test_module(self, r): + def test_module(self, stack_r): with pytest.raises(redis.exceptions.ModuleError) as excinfo: - r.module_load("/some/fake/path") + stack_r.module_load("/some/fake/path") assert "Error loading the extension." in str(excinfo.value) with pytest.raises(redis.exceptions.ModuleError) as excinfo: - r.module_load("/some/fake/path", "arg1", "arg2", "arg3", "arg4") + stack_r.module_load("/some/fake/path", "arg1", "arg2", "arg3", "arg4") assert "Error loading the extension." in str(excinfo.value) @pytest.mark.onlynoncluster @skip_if_server_version_lt("7.0.0") @skip_if_redis_enterprise() - def test_module_loadex(self, r: redis.Redis): + def test_module_loadex(self, stack_r: redis.Redis): with pytest.raises(redis.exceptions.ModuleError) as excinfo: - r.module_loadex("/some/fake/path") + stack_r.module_loadex("/some/fake/path") assert "Error loading the extension." in str(excinfo.value) with pytest.raises(redis.exceptions.ModuleError) as excinfo: - r.module_loadex("/some/fake/path", ["name", "value"], ["arg1", "arg2"]) + stack_r.module_loadex( + "/some/fake/path", ["name", "value"], ["arg1", "arg2"] + ) assert "Error loading the extension." in str(excinfo.value) @skip_if_server_version_lt("2.6.0") diff --git a/tests/test_graph.py b/tests/test_graph.py index c6d128908e..2eace0181c 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -24,18 +24,20 @@ @pytest.fixture -def client(request): - r = _get_client(Redis, request, decode_responses=True) +def client(request, stack_url): + r = _get_client(Redis, request, decode_responses=True, from_url=stack_url) r.flushdb() return r +@pytest.mark.redismod def test_bulk(client): with pytest.raises(NotImplementedError): client.graph().bulk() client.graph().bulk(foo="bar!") +@pytest.mark.redismod def test_graph_creation(client): graph = client.graph() @@ -80,6 +82,7 @@ def test_graph_creation(client): graph.delete() +@pytest.mark.redismod def test_array_functions(client): query = """CREATE (p:person{name:'a',age:32, array:[0,1,2]})""" client.graph().query(query) @@ -100,6 +103,7 @@ def test_array_functions(client): assert [a] == result.result_set[0][0] +@pytest.mark.redismod def test_path(client): node0 = Node(node_id=0, label="L1") node1 = Node(node_id=1, label="L1") @@ -119,6 +123,7 @@ def test_path(client): assert expected_results == result.result_set +@pytest.mark.redismod def test_param(client): params = [1, 2.3, "str", True, False, None, [0, 1, 2], r"\" RETURN 1337 //"] query = "RETURN $param" @@ -128,6 +133,7 @@ def test_param(client): assert expected_results == result.result_set +@pytest.mark.redismod def test_map(client): query = "RETURN {a:1, b:'str', c:NULL, d:[1,2,3], e:True, f:{x:1, y:2}}" @@ -144,6 +150,7 @@ def test_map(client): assert actual == expected +@pytest.mark.redismod def test_point(client): query = "RETURN point({latitude: 32.070794860, longitude: 34.820751118})" expected_lat = 32.070794860 @@ -160,6 +167,7 @@ def test_point(client): assert abs(actual["longitude"] - expected_lon) < 0.001 +@pytest.mark.redismod def test_index_response(client): result_set = client.graph().query("CREATE INDEX ON :person(age)") assert 1 == result_set.indices_created @@ -174,6 +182,7 @@ def test_index_response(client): client.graph().query("DROP INDEX ON :person(age)") +@pytest.mark.redismod def test_stringify_query_result(client): graph = client.graph() @@ -227,6 +236,7 @@ def test_stringify_query_result(client): graph.delete() +@pytest.mark.redismod def test_optional_match(client): # Build a graph of form (a)-[R]->(b) node0 = Node(node_id=0, label="L1", properties={"value": "a"}) @@ -251,6 +261,7 @@ def test_optional_match(client): graph.delete() +@pytest.mark.redismod def test_cached_execution(client): client.graph().query("CREATE ()") @@ -268,6 +279,7 @@ def test_cached_execution(client): assert cached_result.cached_execution +@pytest.mark.redismod def test_slowlog(client): create_query = """CREATE (:Rider {name:'Valentino Rossi'})-[:rides]->(:Team {name:'Yamaha'}), @@ -280,6 +292,7 @@ def test_slowlog(client): assert results[0][2] == create_query +@pytest.mark.redismod @pytest.mark.xfail(strict=False) def test_query_timeout(client): # Build a sample graph with 1000 nodes. @@ -294,6 +307,7 @@ def test_query_timeout(client): assert False is False +@pytest.mark.redismod def test_read_only_query(client): with pytest.raises(Exception): # Issue a write query, specifying read-only true, @@ -302,6 +316,7 @@ def test_read_only_query(client): assert False is False +@pytest.mark.redismod def test_profile(client): q = """UNWIND range(1, 3) AS x CREATE (p:Person {v:x})""" profile = client.graph().profile(q).result_set @@ -316,6 +331,7 @@ def test_profile(client): assert "Node By Label Scan | (p:Person) | Records produced: 3" in profile +@pytest.mark.redismod @skip_if_redis_enterprise() def test_config(client): config_name = "RESULTSET_SIZE" @@ -348,6 +364,7 @@ def test_config(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod def test_list_keys(client): result = client.graph().list_keys() assert result == [] @@ -370,6 +387,7 @@ def test_list_keys(client): assert result == [] +@pytest.mark.redismod def test_multi_label(client): redis_graph = client.graph("g") @@ -395,6 +413,7 @@ def test_multi_label(client): assert True +@pytest.mark.redismod def test_cache_sync(client): pass return @@ -467,6 +486,7 @@ def test_cache_sync(client): assert A._relationship_types[1] == "R" +@pytest.mark.redismod def test_execution_plan(client): redis_graph = client.graph("execution_plan") create_query = """CREATE @@ -485,6 +505,7 @@ def test_execution_plan(client): redis_graph.delete() +@pytest.mark.redismod def test_explain(client): redis_graph = client.graph("execution_plan") # graph creation / population @@ -573,6 +594,7 @@ def test_explain(client): redis_graph.delete() +@pytest.mark.redismod def test_resultset_statistics(client): with patch.object(target=QueryResult, attribute="_get_stat") as mock_get_stats: result = client.graph().query("RETURN 1") diff --git a/tests/test_json.py b/tests/test_json.py index 73d72b8cc9..5cf9b11e17 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -8,12 +8,13 @@ @pytest.fixture -def client(request): - r = _get_client(Redis, request, decode_responses=True) +def client(request, stack_url): + r = _get_client(Redis, request, decode_responses=True, from_url=stack_url) r.flushdb() return r +@pytest.mark.redismod def test_json_setbinarykey(client): d = {"hello": "world", b"some": "value"} with pytest.raises(TypeError): @@ -21,6 +22,7 @@ def test_json_setbinarykey(client): assert client.json().set("somekey", Path.root_path(), d, decode_keys=True) +@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"]]) @@ -30,11 +32,13 @@ def test_json_setgetdeleteforget(client): assert client.exists("foo") == 0 +@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"]]) +@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"]]) @@ -43,6 +47,7 @@ def test_json_get_jset(client): assert client.exists("foo") == 0 +@pytest.mark.redismod @skip_ifmodversion_lt("2.06.00", "ReJSON") # todo: update after the release def test_json_merge(client): # Test with root path $ @@ -75,6 +80,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" @@ -85,6 +91,7 @@ def test_nonascii_setgetdelete(client): assert client.exists("notascii") == 0 +@pytest.mark.redismod def test_jsonsetexistentialmodifiersshouldsucceed(client): obj = {"foo": "bar"} assert client.json().set("obj", Path.root_path(), obj) @@ -102,6 +109,7 @@ def test_jsonsetexistentialmodifiersshouldsucceed(client): client.json().set("obj", Path("foo"), "baz", nx=True, xx=True) +@pytest.mark.redismod def test_mgetshouldsucceed(client): client.json().set("1", Path.root_path(), 1) client.json().set("2", Path.root_path(), 2) @@ -111,6 +119,7 @@ def test_mgetshouldsucceed(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("2.06.00", "ReJSON") def test_mset(client): client.json().mset([("1", Path.root_path(), 1), ("2", Path.root_path(), 2)]) @@ -119,6 +128,7 @@ def test_mset(client): assert client.json().mget(["1", "2"], Path.root_path()) == [1, 2] +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "ReJSON") # todo: update after the release def test_clear(client): client.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) @@ -126,6 +136,7 @@ def test_clear(client): assert_resp_response(client, client.json().get("arr"), [], [[[]]]) +@pytest.mark.redismod def test_type(client): client.json().set("1", Path.root_path(), 1) assert_resp_response( @@ -134,6 +145,7 @@ def test_type(client): assert_resp_response(client, client.json().type("1"), "integer", ["integer"]) +@pytest.mark.redismod def test_numincrby(client): client.json().set("num", Path.root_path(), 1) assert_resp_response( @@ -147,6 +159,7 @@ def test_numincrby(client): ) +@pytest.mark.redismod def test_nummultby(client): client.json().set("num", Path.root_path(), 1) @@ -162,6 +175,7 @@ def test_nummultby(client): ) +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "ReJSON") # todo: update after the release def test_toggle(client): client.json().set("bool", Path.root_path(), False) @@ -173,6 +187,7 @@ def test_toggle(client): client.json().toggle("num", Path.root_path()) +@pytest.mark.redismod def test_strappend(client): client.json().set("jsonkey", Path.root_path(), "foo") assert 6 == client.json().strappend("jsonkey", "bar") @@ -181,15 +196,7 @@ def test_strappend(client): ) -# # def test_debug(client): -# client.json().set("str", Path.root_path(), "foo") -# assert 24 == client.json().debug("MEMORY", "str", Path.root_path()) -# assert 24 == client.json().debug("MEMORY", "str") -# -# # technically help is valid -# assert isinstance(client.json().debug("HELP"), list) - - +@pytest.mark.redismod def test_strlen(client): client.json().set("str", Path.root_path(), "foo") assert 3 == client.json().strlen("str", Path.root_path()) @@ -198,6 +205,7 @@ def test_strlen(client): assert 6 == client.json().strlen("str") +@pytest.mark.redismod def test_arrappend(client): client.json().set("arr", Path.root_path(), [1]) assert 2 == client.json().arrappend("arr", Path.root_path(), 2) @@ -205,6 +213,7 @@ def test_arrappend(client): assert 7 == client.json().arrappend("arr", Path.root_path(), *[5, 6, 7]) +@pytest.mark.redismod def test_arrindex(client): client.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) assert 1 == client.json().arrindex("arr", Path.root_path(), 1) @@ -216,6 +225,7 @@ def test_arrindex(client): assert -1 == client.json().arrindex("arr", Path.root_path(), 4, start=1, stop=3) +@pytest.mark.redismod 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]) @@ -229,6 +239,7 @@ def test_arrinsert(client): assert_resp_response(client, client.json().get("val2"), res, [[res]]) +@pytest.mark.redismod def test_arrlen(client): client.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) assert 5 == client.json().arrlen("arr", Path.root_path()) @@ -236,6 +247,7 @@ def test_arrlen(client): assert client.json().arrlen("fakekey") is None +@pytest.mark.redismod def test_arrpop(client): client.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4]) assert 4 == client.json().arrpop("arr", Path.root_path(), 4) @@ -253,6 +265,7 @@ def test_arrpop(client): assert client.json().arrpop("arr") is None +@pytest.mark.redismod 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) @@ -275,6 +288,7 @@ def test_arrtrim(client): assert 0 == client.json().arrtrim("arr", Path.root_path(), 9, 11) +@pytest.mark.redismod def test_resp(client): obj = {"foo": "bar", "baz": 1, "qaz": True} client.json().set("obj", Path.root_path(), obj) @@ -284,6 +298,7 @@ def test_resp(client): assert isinstance(client.json().resp("obj"), list) +@pytest.mark.redismod def test_objkeys(client): obj = {"foo": "bar", "baz": "qaz"} client.json().set("obj", Path.root_path(), obj) @@ -300,6 +315,7 @@ def test_objkeys(client): assert client.json().objkeys("fakekey") is None +@pytest.mark.redismod def test_objlen(client): obj = {"foo": "bar", "baz": "qaz"} client.json().set("obj", Path.root_path(), obj) @@ -309,6 +325,7 @@ def test_objlen(client): assert len(obj) == client.json().objlen("obj") +@pytest.mark.redismod def test_json_commands_in_pipeline(client): p = client.json().pipeline() p.set("foo", Path.root_path(), "bar") @@ -332,6 +349,7 @@ def test_json_commands_in_pipeline(client): assert client.get("foo") is None +@pytest.mark.redismod def test_json_delete_with_dollar(client): doc1 = {"a": 1, "nested": {"a": 2, "b": 3}} assert client.json().set("doc1", "$", doc1) @@ -383,6 +401,7 @@ def test_json_delete_with_dollar(client): client.json().delete("not_a_document", "..a") +@pytest.mark.redismod def test_json_forget_with_dollar(client): doc1 = {"a": 1, "nested": {"a": 2, "b": 3}} assert client.json().set("doc1", "$", doc1) @@ -434,6 +453,7 @@ def test_json_forget_with_dollar(client): client.json().forget("not_a_document", "..a") +@pytest.mark.redismod def test_json_mget_dollar(client): # Test mget with multi paths client.json().set( @@ -463,6 +483,7 @@ def test_json_mget_dollar(client): assert res == [None, None] +@pytest.mark.redismod def test_numby_commands_dollar(client): # Test NUMINCRBY client.json().set("doc1", "$", {"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}) @@ -506,6 +527,7 @@ def test_numby_commands_dollar(client): client.json().nummultby("doc1", ".b[0].a", 3) == 6 +@pytest.mark.redismod def test_strappend_dollar(client): client.json().set( "doc1", "$", {"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}} @@ -536,6 +558,7 @@ def test_strappend_dollar(client): client.json().strappend("doc1", "piu") +@pytest.mark.redismod def test_strlen_dollar(client): # Test multi client.json().set( @@ -556,6 +579,7 @@ def test_strlen_dollar(client): client.json().strlen("non_existing_doc", "$..a") +@pytest.mark.redismod def test_arrappend_dollar(client): client.json().set( "doc1", @@ -630,6 +654,7 @@ def test_arrappend_dollar(client): client.json().arrappend("non_existing_doc", "$..a") +@pytest.mark.redismod def test_arrinsert_dollar(client): client.json().set( "doc1", @@ -668,6 +693,7 @@ def test_arrinsert_dollar(client): client.json().arrappend("non_existing_doc", "$..a") +@pytest.mark.redismod def test_arrlen_dollar(client): client.json().set( "doc1", @@ -716,6 +742,7 @@ def test_arrlen_dollar(client): assert client.json().arrlen("non_existing_doc", "..a") is None +@pytest.mark.redismod def test_arrpop_dollar(client): client.json().set( "doc1", @@ -757,6 +784,7 @@ def test_arrpop_dollar(client): client.json().arrpop("non_existing_doc", "..a") +@pytest.mark.redismod def test_arrtrim_dollar(client): client.json().set( "doc1", @@ -809,6 +837,7 @@ def test_arrtrim_dollar(client): client.json().arrtrim("non_existing_doc", "..a", 1, 1) +@pytest.mark.redismod def test_objkeys_dollar(client): client.json().set( "doc1", @@ -838,6 +867,7 @@ def test_objkeys_dollar(client): assert client.json().objkeys("doc1", "$..nowhere") == [] +@pytest.mark.redismod def test_objlen_dollar(client): client.json().set( "doc1", @@ -892,6 +922,7 @@ def load_types_data(nested_key_name): return jdata, types +@pytest.mark.redismod def test_type_dollar(client): jdata, jtypes = load_types_data("a") client.json().set("doc1", "$", jdata) @@ -909,6 +940,7 @@ def test_type_dollar(client): ) +@pytest.mark.redismod def test_clear_dollar(client): client.json().set( "doc1", @@ -959,6 +991,7 @@ def test_clear_dollar(client): client.json().clear("non_existing_doc", "$..a") +@pytest.mark.redismod def test_toggle_dollar(client): client.json().set( "doc1", @@ -987,28 +1020,7 @@ def test_toggle_dollar(client): client.json().toggle("non_existing_doc", "$..a") -# # def test_debug_dollar(client): -# -# jdata, jtypes = load_types_data("a") -# -# client.json().set("doc1", "$", jdata) -# -# # Test multi -# assert client.json().debug("MEMORY", "doc1", "$..a") == [72, 24, 24, 16, 16, 1, 0] -# -# # Test single -# assert client.json().debug("MEMORY", "doc1", "$.nested2.a") == [24] -# -# # Test legacy -# assert client.json().debug("MEMORY", "doc1", "..a") == 72 -# -# # Test missing path (defaults to root) -# assert client.json().debug("MEMORY", "doc1") == 72 -# -# # Test missing key -# assert client.json().debug("MEMORY", "non_existing_doc", "$..a") == [] - - +@pytest.mark.redismod def test_resp_dollar(client): data = { "L1": { @@ -1237,6 +1249,7 @@ def test_resp_dollar(client): client.json().resp("non_existing_doc", "$..a") +@pytest.mark.redismod def test_arrindex_dollar(client): client.json().set( "store", @@ -1462,6 +1475,7 @@ def test_arrindex_dollar(client): assert client.json().arrindex("test_None", "..nested2_not_found.arr", "None") == 0 +@pytest.mark.redismod def test_decoders_and_unstring(): assert unstring("4") == 4 assert unstring("45.55") == 45.55 @@ -1472,6 +1486,7 @@ def test_decoders_and_unstring(): assert decode_list(["hello", b"world"]) == ["hello", "world"] +@pytest.mark.redismod def test_custom_decoder(client): import json @@ -1487,6 +1502,7 @@ def test_custom_decoder(client): assert not isinstance(cj.__decoder__, json.JSONDecoder) +@pytest.mark.redismod def test_set_file(client): import json import tempfile @@ -1505,6 +1521,7 @@ def test_set_file(client): client.json().set_file("test2", Path.root_path(), nojsonfile.name) +@pytest.mark.redismod def test_set_path(client): import json import tempfile diff --git a/tests/test_search.py b/tests/test_search.py index f19c193891..6b40c5129d 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -107,8 +107,8 @@ def createIndex(client, num_docs=100, definition=None): @pytest.fixture -def client(request): - r = _get_client(redis.Redis, request, decode_responses=True) +def client(request, stack_url): + r = _get_client(redis.Redis, request, decode_responses=True, from_url=stack_url) r.flushdb() return r diff --git a/tests/test_timeseries.py b/tests/test_timeseries.py index 6b59967f3c..5318818e79 100644 --- a/tests/test_timeseries.py +++ b/tests/test_timeseries.py @@ -5,7 +5,20 @@ import pytest import redis -from .conftest import assert_resp_response, is_resp2_connection, skip_ifmodversion_lt +from .conftest import ( + _get_client, + assert_resp_response, + is_resp2_connection, + skip_ifmodversion_lt, +) + + +@pytest.fixture() +def decoded_r(request, stack_url): + with _get_client( + redis.Redis, request, decode_responses=True, from_url=stack_url + ) as client: + yield client @pytest.fixture @@ -14,6 +27,7 @@ def client(decoded_r): return decoded_r +@pytest.mark.redismod def test_create(client): assert client.ts().create(1) assert client.ts().create(2, retention_msecs=5) @@ -31,6 +45,7 @@ def test_create(client): assert_resp_response(client, 128, info.get("chunk_size"), info.get("chunkSize")) +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") def test_create_duplicate_policy(client): # Test for duplicate policy @@ -46,6 +61,7 @@ def test_create_duplicate_policy(client): ) +@pytest.mark.redismod def test_alter(client): assert client.ts().create(1) info = client.ts().info(1) @@ -66,6 +82,7 @@ def test_alter(client): ) +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") def test_alter_diplicate_policy(client): assert client.ts().create(1) @@ -80,6 +97,7 @@ def test_alter_diplicate_policy(client): ) +@pytest.mark.redismod def test_add(client): assert 1 == client.ts().add(1, 1, 1) assert 2 == client.ts().add(2, 2, 3, retention_msecs=10) @@ -102,6 +120,7 @@ def test_add(client): assert_resp_response(client, 128, info.get("chunk_size"), info.get("chunkSize")) +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") def test_add_duplicate_policy(client): # Test for duplicate policy BLOCK @@ -138,11 +157,13 @@ def test_add_duplicate_policy(client): assert 5.0 == client.ts().get("time-serie-add-ooo-min")[1] +@pytest.mark.redismod def test_madd(client): client.ts().create("a") assert [1, 2, 3] == client.ts().madd([("a", 1, 5), ("a", 2, 10), ("a", 3, 15)]) +@pytest.mark.redismod def test_incrby_decrby(client): for _ in range(100): assert client.ts().incrby(1, 1) @@ -171,6 +192,7 @@ def test_incrby_decrby(client): assert_resp_response(client, 128, info.get("chunk_size"), info.get("chunkSize")) +@pytest.mark.redismod def test_create_and_delete_rule(client): # test rule creation time = 100 @@ -194,6 +216,7 @@ def test_create_and_delete_rule(client): assert not info["rules"] +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") def test_del_range(client): try: @@ -208,6 +231,7 @@ def test_del_range(client): assert_resp_response(client, client.ts().range(1, 22, 22), [(22, 1.0)], [[22, 1.0]]) +@pytest.mark.redismod def test_range(client): for i in range(100): client.ts().add(1, i, i % 7) @@ -222,6 +246,7 @@ def test_range(client): assert 10 == len(client.ts().range(1, 0, 500, count=10)) +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") def test_range_advanced(client): for i in range(100): @@ -251,6 +276,7 @@ def test_range_advanced(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_range_latest(client: redis.Redis): timeseries = client.ts() @@ -275,6 +301,7 @@ def test_range_latest(client: redis.Redis): ) +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_range_bucket_timestamp(client: redis.Redis): timeseries = client.ts() @@ -308,6 +335,7 @@ def test_range_bucket_timestamp(client: redis.Redis): ) +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_range_empty(client: redis.Redis): timeseries = client.ts() @@ -352,6 +380,7 @@ def test_range_empty(client: redis.Redis): assert_resp_response(client, res, resp2_expected, resp3_expected) +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") def test_rev_range(client): for i in range(100): @@ -400,6 +429,7 @@ def test_rev_range(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_revrange_latest(client: redis.Redis): timeseries = client.ts() @@ -418,6 +448,7 @@ def test_revrange_latest(client: redis.Redis): assert_resp_response(client, res, [(0, 4.0)], [[0, 4.0]]) +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_revrange_bucket_timestamp(client: redis.Redis): timeseries = client.ts() @@ -451,6 +482,7 @@ def test_revrange_bucket_timestamp(client: redis.Redis): ) +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_revrange_empty(client: redis.Redis): timeseries = client.ts() @@ -496,6 +528,7 @@ def test_revrange_empty(client: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod def test_mrange(client): client.ts().create(1, labels={"Test": "This", "team": "ny"}) client.ts().create(2, labels={"Test": "This", "Taste": "That", "team": "sf"}) @@ -544,6 +577,7 @@ def test_mrange(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") def test_multi_range_advanced(client): client.ts().create(1, labels={"Test": "This", "team": "ny"}) @@ -657,6 +691,7 @@ def test_multi_range_advanced(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_mrange_latest(client: redis.Redis): timeseries = client.ts() @@ -686,6 +721,7 @@ def test_mrange_latest(client: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("99.99.99", "timeseries") def test_multi_reverse_range(client): client.ts().create(1, labels={"Test": "This", "team": "ny"}) @@ -804,6 +840,7 @@ def test_multi_reverse_range(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_mrevrange_latest(client: redis.Redis): timeseries = client.ts() @@ -832,6 +869,7 @@ def test_mrevrange_latest(client: redis.Redis): ) +@pytest.mark.redismod def test_get(client): name = "test" client.ts().create(name) @@ -843,6 +881,7 @@ def test_get(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_get_latest(client: redis.Redis): timeseries = client.ts() @@ -860,6 +899,7 @@ def test_get_latest(client: redis.Redis): @pytest.mark.onlynoncluster +@pytest.mark.redismod def test_mget(client): client.ts().create(1, labels={"Test": "This"}) client.ts().create(2, labels={"Test": "This", "Taste": "That"}) @@ -895,6 +935,7 @@ def test_mget(client): @pytest.mark.onlynoncluster +@pytest.mark.redismod @skip_ifmodversion_lt("1.8.0", "timeseries") def test_mget_latest(client: redis.Redis): timeseries = client.ts() @@ -911,6 +952,7 @@ def test_mget_latest(client: redis.Redis): assert_resp_response(client, res, [{"t2": [{}, 10, 8.0]}], {"t2": [{}, [10, 8.0]]}) +@pytest.mark.redismod def test_info(client): client.ts().create(1, retention_msecs=5, labels={"currentLabel": "currentData"}) info = client.ts().info(1) @@ -920,8 +962,9 @@ def test_info(client): assert info["labels"]["currentLabel"] == "currentData" +@pytest.mark.redismod @skip_ifmodversion_lt("1.4.0", "timeseries") -def testInfoDuplicatePolicy(client): +def test_info_duplicate_policy(client): client.ts().create(1, retention_msecs=5, labels={"currentLabel": "currentData"}) info = client.ts().info(1) assert_resp_response( @@ -935,6 +978,7 @@ def testInfoDuplicatePolicy(client): ) +@pytest.mark.redismod @pytest.mark.onlynoncluster def test_query_index(client): client.ts().create(1, labels={"Test": "This"}) @@ -944,6 +988,7 @@ def test_query_index(client): assert_resp_response(client, client.ts().queryindex(["Taste=That"]), [2], {"2"}) +@pytest.mark.redismod def test_pipeline(client): pipeline = client.ts().pipeline() pipeline.create("with_pipeline") @@ -961,6 +1006,7 @@ def test_pipeline(client): assert client.ts().get("with_pipeline")[1] == 99 * 1.1 +@pytest.mark.redismod def test_uncompressed(client): client.ts().create("compressed") client.ts().create("uncompressed", uncompressed=True)