mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-10 18:05:44 +02:00
parent
44fbe09108
commit
1958e09a9a
23 changed files with 311 additions and 1203 deletions
2
.github/workflows/test-fakeredis.yml
vendored
2
.github/workflows/test-fakeredis.yml
vendored
|
@ -75,8 +75,6 @@ jobs:
|
|||
run: |
|
||||
poetry run pytest test/ \
|
||||
--ignore test/test_hypothesis.py \
|
||||
--ignore test/test_geo_commands.py \
|
||||
--ignore test/test_bitmap_commands.py \
|
||||
--ignore test/test_json/ \
|
||||
--ignore test/test_mixins/test_bitmap_commands.py \
|
||||
--junit-xml=results-tests.xml --html=report-tests.html -v
|
||||
|
|
50
tests/fakeredis/poetry.lock
generated
50
tests/fakeredis/poetry.lock
generated
|
@ -144,22 +144,22 @@ test = ["pytest (>=6)"]
|
|||
|
||||
[[package]]
|
||||
name = "fakeredis"
|
||||
version = "2.23.5"
|
||||
version = "2.25.1"
|
||||
description = "Python implementation of redis API, can be used for testing purposes."
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.7"
|
||||
files = [
|
||||
{file = "fakeredis-2.23.5-py3-none-any.whl", hash = "sha256:4d85b1b6b3a80cbbb3a8967f8686f7bf6ddf5bd7cd5ac7ac90b3561d8c3a7ddb"},
|
||||
{file = "fakeredis-2.23.5.tar.gz", hash = "sha256:edffc79fdce0f1d83cbb20b52694a9cba4a5fe5beb627c11722a42aa0fa44f52"},
|
||||
{file = "fakeredis-2.25.1-py3-none-any.whl", hash = "sha256:d08dcbaceae0804db4644fa634106e3c42d76fe4d11aea2949eda768df0c6450"},
|
||||
{file = "fakeredis-2.25.1.tar.gz", hash = "sha256:e9e73bacf412d1d942ee7f80525dc188182158e82d41be57eb9c4e71f7474ac8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
jsonpath-ng = {version = ">=1.6,<2.0", optional = true, markers = "extra == \"json\""}
|
||||
lupa = {version = ">=2.1,<3.0", optional = true, markers = "extra == \"lua\""}
|
||||
pyprobables = {version = ">=0.6,<0.7", optional = true, markers = "extra == \"bf\" or extra == \"cf\" or extra == \"probabilistic\""}
|
||||
redis = ">=4"
|
||||
redis = {version = ">=4.3", markers = "python_full_version > \"3.8.0\""}
|
||||
sortedcontainers = ">=2,<3"
|
||||
typing_extensions = {version = ">=4.7,<5.0", markers = "python_version < \"3.11\""}
|
||||
typing-extensions = {version = ">=4.7,<5.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
bf = ["pyprobables (>=0.6,<0.7)"]
|
||||
|
@ -170,13 +170,13 @@ probabilistic = ["pyprobables (>=0.6,<0.7)"]
|
|||
|
||||
[[package]]
|
||||
name = "hypothesis"
|
||||
version = "6.111.1"
|
||||
version = "6.112.2"
|
||||
description = "A library for property-based testing"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "hypothesis-6.111.1-py3-none-any.whl", hash = "sha256:9422adbac4b2104f6cf92dc6604b5c9df975efc08ffc7145ecc39bc617243835"},
|
||||
{file = "hypothesis-6.111.1.tar.gz", hash = "sha256:6ab6185a858fa692bf125c0d0a936134edc318bee01c05e407c71c9ead0b61c5"},
|
||||
{file = "hypothesis-6.112.2-py3-none-any.whl", hash = "sha256:914b55f75b7c6f653cd36fef66b61a773a51c1e363939fcbc0216773ff4ee0d9"},
|
||||
{file = "hypothesis-6.112.2.tar.gz", hash = "sha256:90cd62d9487eaf294bf0dceb47dbaca6432408b2e9417cfa6e3409313dbde95b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -185,10 +185,10 @@ exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
|||
sortedcontainers = ">=2.1.0,<3.0.0"
|
||||
|
||||
[package.extras]
|
||||
all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "crosshair-tool (>=0.0.66)", "django (>=3.2)", "dpcontracts (>=0.4)", "hypothesis-crosshair (>=0.0.12)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.17.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2024.1)"]
|
||||
all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "crosshair-tool (>=0.0.72)", "django (>=3.2)", "dpcontracts (>=0.4)", "hypothesis-crosshair (>=0.0.14)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.17.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2024.2)"]
|
||||
cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"]
|
||||
codemods = ["libcst (>=0.3.16)"]
|
||||
crosshair = ["crosshair-tool (>=0.0.66)", "hypothesis-crosshair (>=0.0.12)"]
|
||||
crosshair = ["crosshair-tool (>=0.0.72)", "hypothesis-crosshair (>=0.0.14)"]
|
||||
dateutil = ["python-dateutil (>=1.4)"]
|
||||
django = ["django (>=3.2)"]
|
||||
dpcontracts = ["dpcontracts (>=0.4)"]
|
||||
|
@ -199,7 +199,7 @@ pandas = ["pandas (>=1.1)"]
|
|||
pytest = ["pytest (>=4.6)"]
|
||||
pytz = ["pytz (>=2014.1)"]
|
||||
redis = ["redis (>=3.0.0)"]
|
||||
zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2024.1)"]
|
||||
zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2024.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
|
@ -457,13 +457,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.3.2"
|
||||
version = "8.3.3"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"},
|
||||
{file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"},
|
||||
{file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"},
|
||||
{file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -583,21 +583,21 @@ pytest = ">=7.0.0"
|
|||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "5.0.8"
|
||||
version = "5.1.0"
|
||||
description = "Python client for Redis database and key-value store"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "redis-5.0.8-py3-none-any.whl", hash = "sha256:56134ee08ea909106090934adc36f65c9bcbbaecea5b21ba704ba6fb561f8eb4"},
|
||||
{file = "redis-5.0.8.tar.gz", hash = "sha256:0c5b10d387568dfe0698c6fad6615750c24170e548ca2deac10c649d463e9870"},
|
||||
{file = "redis-5.1.0-py3-none-any.whl", hash = "sha256:fd4fccba0d7f6aa48c58a78d76ddb4afc698f5da4a2c1d03d916e4fd7ab88cdd"},
|
||||
{file = "redis-5.1.0.tar.gz", hash = "sha256:b756df1e4a3858fcc0ef861f3fc53623a96c41e2b1f5304e09e0fe758d333d40"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""}
|
||||
|
||||
[package.extras]
|
||||
hiredis = ["hiredis (>1.0.0)"]
|
||||
ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
|
||||
hiredis = ["hiredis (>=3.0.0)"]
|
||||
ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "sortedcontainers"
|
||||
|
@ -612,13 +612,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
{file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"},
|
||||
{file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -635,4 +635,4 @@ files = [
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "942f6f5d521576b80ff3df540956c1d9c16826b9d82bd4f9b15d439a1df98f9c"
|
||||
content-hash = "c7fb24a461b6c934fb5ef67a10701aff7bab809ee76c3cff267959c9798a6a81"
|
||||
|
|
|
@ -19,7 +19,7 @@ maintainers = [
|
|||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
redis = ">=5"
|
||||
fakeredis = { version = "^2.23", extras = ["json", "bf", "cf", "lua"] }
|
||||
fakeredis = { version = "^2.25", extras = ["json", "bf", "cf", "lua"] }
|
||||
hypothesis = "^6.111"
|
||||
pytest = "^8.3"
|
||||
pytest-timeout = "^2.3.1"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import asyncio
|
||||
import re
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
|
@ -11,14 +10,10 @@ import pytest_asyncio
|
|||
import redis
|
||||
import redis.asyncio
|
||||
|
||||
from fakeredis import FakeServer, aioredis, FakeAsyncRedis, FakeStrictRedis
|
||||
from fakeredis import FakeServer, aioredis
|
||||
from test import testtools
|
||||
|
||||
|
||||
pytestmark = []
|
||||
fake_only = pytest.mark.parametrize(
|
||||
"async_redis", [pytest.param("fake", marks=pytest.mark.fake)], indirect=True
|
||||
)
|
||||
pytestmark.extend(
|
||||
[
|
||||
pytest.mark.asyncio,
|
||||
|
@ -183,31 +178,6 @@ class TestScripts:
|
|||
await async_redis.eval('return redis.call("ZCOUNT", KEYS[1])', 1, "foo")
|
||||
|
||||
|
||||
@testtools.run_test_if_redispy_ver("gte", "5.1")
|
||||
async def test_repr_redis_51(async_redis: redis.asyncio.Redis):
|
||||
assert re.fullmatch(
|
||||
r"<redis.asyncio.connection.ConnectionPool("
|
||||
r"<fakeredis.aioredis.FakeConnection(server=<fakeredis._server.FakeServer object at .*>,db=0)>)>",
|
||||
repr(async_redis.connection_pool),
|
||||
)
|
||||
|
||||
|
||||
@fake_only
|
||||
@pytest.mark.disconnected
|
||||
async def test_not_connected(async_redis: redis.asyncio.Redis):
|
||||
with pytest.raises(redis.asyncio.ConnectionError):
|
||||
await async_redis.ping()
|
||||
|
||||
|
||||
@fake_only
|
||||
async def test_disconnect_server(async_redis, fake_server):
|
||||
await async_redis.ping()
|
||||
fake_server.connected = False
|
||||
with pytest.raises(redis.asyncio.ConnectionError):
|
||||
await async_redis.ping()
|
||||
fake_server.connected = True
|
||||
|
||||
|
||||
async def test_type(async_redis: redis.asyncio.Redis):
|
||||
await async_redis.set("string_key", "value")
|
||||
await async_redis.lpush("list_key", "value")
|
||||
|
@ -238,78 +208,6 @@ async def test_xdel(async_redis: redis.asyncio.Redis):
|
|||
assert await async_redis.xdel(stream, m2, m3) == 2
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
async def test_from_url():
|
||||
r0 = aioredis.FakeRedis.from_url("redis://localhost?db=0")
|
||||
r1 = aioredis.FakeRedis.from_url("redis://localhost?db=1")
|
||||
# Check that they are indeed different databases
|
||||
await r0.set("foo", "a")
|
||||
await r1.set("foo", "b")
|
||||
assert await r0.get("foo") == b"a"
|
||||
assert await r1.get("foo") == b"b"
|
||||
await r0.connection_pool.disconnect()
|
||||
await r1.connection_pool.disconnect()
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
async def test_from_url_with_version():
|
||||
r0 = aioredis.FakeRedis.from_url("redis://localhost?db=0", version=(6,))
|
||||
r1 = aioredis.FakeRedis.from_url("redis://localhost?db=1", version=(6,))
|
||||
# Check that they are indeed different databases
|
||||
await r0.set("foo", "a")
|
||||
await r1.set("foo", "b")
|
||||
assert await r0.get("foo") == b"a"
|
||||
assert await r1.get("foo") == b"b"
|
||||
await r0.connection_pool.disconnect()
|
||||
await r1.connection_pool.disconnect()
|
||||
|
||||
|
||||
@fake_only
|
||||
async def test_from_url_with_server(async_redis, fake_server):
|
||||
r2 = aioredis.FakeRedis.from_url("redis://localhost", server=fake_server)
|
||||
await async_redis.set("foo", "bar")
|
||||
assert await r2.get("foo") == b"bar"
|
||||
await r2.connection_pool.disconnect()
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
async def test_without_server():
|
||||
r = aioredis.FakeRedis()
|
||||
assert await r.ping()
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
async def test_without_server_disconnected():
|
||||
r = aioredis.FakeRedis(connected=False)
|
||||
with pytest.raises(redis.asyncio.ConnectionError):
|
||||
await r.ping()
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
async def test_async():
|
||||
# arrange
|
||||
cache = aioredis.FakeRedis()
|
||||
# act
|
||||
await cache.set("fakeredis", "plz")
|
||||
x = await cache.get("fakeredis")
|
||||
# assert
|
||||
assert x == b"plz"
|
||||
|
||||
|
||||
@testtools.run_test_if_redispy_ver("gte", "4.4.0")
|
||||
@pytest.mark.parametrize("nowait", [False, True])
|
||||
@pytest.mark.fake
|
||||
async def test_connection_disconnect(nowait):
|
||||
server = FakeServer()
|
||||
r = aioredis.FakeRedis(server=server)
|
||||
conn = await r.connection_pool.get_connection("_")
|
||||
assert conn is not None
|
||||
|
||||
await conn.disconnect(nowait=nowait)
|
||||
|
||||
assert conn._sock is None
|
||||
|
||||
|
||||
async def test_connection_with_username_and_password():
|
||||
server = FakeServer()
|
||||
r = aioredis.FakeRedis(server=server, username="username", password="password")
|
||||
|
@ -320,31 +218,6 @@ async def test_connection_with_username_and_password():
|
|||
assert result.decode() == test_value
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
async def test_init_args():
|
||||
sync_r1 = FakeStrictRedis()
|
||||
r1 = FakeAsyncRedis()
|
||||
r5 = FakeAsyncRedis()
|
||||
r2 = FakeAsyncRedis(server=FakeServer())
|
||||
|
||||
shared_server = FakeServer()
|
||||
r3 = FakeAsyncRedis(server=shared_server)
|
||||
r4 = FakeAsyncRedis(server=shared_server)
|
||||
|
||||
await r1.set("foo", "bar")
|
||||
await r3.set("bar", "baz")
|
||||
|
||||
assert await r1.get("foo") == b"bar"
|
||||
assert await r5.get("foo") is None
|
||||
assert sync_r1.get("foo") is None
|
||||
assert await r2.get("foo") is None
|
||||
assert await r3.get("foo") is None
|
||||
|
||||
assert await r3.get("bar") == b"baz"
|
||||
assert await r4.get("bar") == b"baz"
|
||||
assert await r1.get("bar") is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cause_fakeredis_bug(async_redis):
|
||||
if sys.version_info < (3, 11):
|
||||
|
|
|
@ -1,484 +0,0 @@
|
|||
from test import testtools
|
||||
|
||||
import pytest
|
||||
import redis
|
||||
import redis.client
|
||||
from fakeredis import _msgs as msgs
|
||||
from redis.exceptions import ResponseError
|
||||
from test.testtools import raw_command
|
||||
|
||||
|
||||
def test_ping(r: redis.Redis):
|
||||
assert r.ping()
|
||||
assert testtools.raw_command(r, "ping", "test") == b"test"
|
||||
with pytest.raises(
|
||||
redis.ResponseError, match=msgs.WRONG_ARGS_MSG6.format("ping")[4:]
|
||||
):
|
||||
raw_command(r, "ping", "arg1", "arg2")
|
||||
|
||||
|
||||
def test_echo(r: redis.Redis):
|
||||
assert r.echo(b"hello") == b"hello"
|
||||
assert r.echo("hello") == b"hello"
|
||||
|
||||
|
||||
@testtools.fake_only
|
||||
def test_time(r, mocker):
|
||||
fake_time = mocker.patch("time.time")
|
||||
fake_time.return_value = 1234567890.1234567
|
||||
assert r.time() == (1234567890, 123457)
|
||||
fake_time.return_value = 1234567890.000001
|
||||
assert r.time() == (1234567890, 1)
|
||||
fake_time.return_value = 1234567890.9999999
|
||||
assert r.time() == (1234567891, 0)
|
||||
|
||||
|
||||
@pytest.mark.decode_responses
|
||||
class TestDecodeResponses:
|
||||
def test_decode_str(self, r):
|
||||
r.set("foo", "bar")
|
||||
assert r.get("foo") == "bar"
|
||||
|
||||
def test_decode_set(self, r):
|
||||
r.sadd("foo", "member1")
|
||||
assert r.smembers("foo") == {"member1"}
|
||||
|
||||
def test_decode_list(self, r):
|
||||
r.rpush("foo", "a", "b")
|
||||
assert r.lrange("foo", 0, -1) == ["a", "b"]
|
||||
|
||||
def test_decode_dict(self, r):
|
||||
r.hset("foo", "key", "value")
|
||||
assert r.hgetall("foo") == {"key": "value"}
|
||||
|
||||
def test_decode_error(self, r):
|
||||
r.set("foo", "bar")
|
||||
with pytest.raises(ResponseError) as exc_info:
|
||||
r.hset("foo", "bar", "baz")
|
||||
assert isinstance(exc_info.value.args[0], str)
|
||||
|
||||
|
||||
@pytest.mark.disconnected
|
||||
@testtools.fake_only
|
||||
class TestFakeStrictRedisConnectionErrors:
|
||||
def test_flushdb(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.flushdb()
|
||||
|
||||
def test_flushall(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.flushall()
|
||||
|
||||
def test_append(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.append("key", "value")
|
||||
|
||||
def test_bitcount(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.bitcount("key", 0, 20)
|
||||
|
||||
def test_decr(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.decr("key", 2)
|
||||
|
||||
def test_exists(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.exists("key")
|
||||
|
||||
def test_expire(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.expire("key", 20)
|
||||
|
||||
def test_pexpire(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.pexpire("key", 20)
|
||||
|
||||
def test_echo(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.echo("value")
|
||||
|
||||
def test_get(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.get("key")
|
||||
|
||||
def test_getbit(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.getbit("key", 2)
|
||||
|
||||
def test_getset(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.getset("key", "value")
|
||||
|
||||
def test_incr(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.incr("key")
|
||||
|
||||
def test_incrby(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.incrby("key")
|
||||
|
||||
def test_ncrbyfloat(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.incrbyfloat("key")
|
||||
|
||||
def test_keys(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.keys()
|
||||
|
||||
def test_mget(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.mget(["key1", "key2"])
|
||||
|
||||
def test_mset(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.mset({"key": "value"})
|
||||
|
||||
def test_msetnx(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.msetnx({"key": "value"})
|
||||
|
||||
def test_persist(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.persist("key")
|
||||
|
||||
def test_rename(self, r):
|
||||
server = r.connection_pool.connection_kwargs["server"]
|
||||
server.connected = True
|
||||
r.set("key1", "value")
|
||||
server.connected = False
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.rename("key1", "key2")
|
||||
server.connected = True
|
||||
assert r.exists("key1")
|
||||
|
||||
def test_eval(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.eval("", 0)
|
||||
|
||||
def test_lpush(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lpush("name", 1, 2)
|
||||
|
||||
def test_lrange(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lrange("name", 1, 5)
|
||||
|
||||
def test_llen(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.llen("name")
|
||||
|
||||
def test_lrem(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lrem("name", 2, 2)
|
||||
|
||||
def test_rpush(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.rpush("name", 1)
|
||||
|
||||
def test_lpop(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lpop("name")
|
||||
|
||||
def test_lset(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lset("name", 1, 4)
|
||||
|
||||
def test_rpushx(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.rpushx("name", 1)
|
||||
|
||||
def test_ltrim(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.ltrim("name", 1, 4)
|
||||
|
||||
def test_lindex(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lindex("name", 1)
|
||||
|
||||
def test_lpushx(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lpushx("name", 1)
|
||||
|
||||
def test_rpop(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.rpop("name")
|
||||
|
||||
def test_linsert(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.linsert("name", "where", "refvalue", "value")
|
||||
|
||||
def test_rpoplpush(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.rpoplpush("src", "dst")
|
||||
|
||||
def test_blpop(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.blpop("keys")
|
||||
|
||||
def test_brpop(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.brpop("keys")
|
||||
|
||||
def test_brpoplpush(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.brpoplpush("src", "dst")
|
||||
|
||||
def test_hdel(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hdel("name")
|
||||
|
||||
def test_hexists(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hexists("name", "key")
|
||||
|
||||
def test_hget(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hget("name", "key")
|
||||
|
||||
def test_hgetall(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hgetall("name")
|
||||
|
||||
def test_hincrby(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hincrby("name", "key")
|
||||
|
||||
def test_hincrbyfloat(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hincrbyfloat("name", "key")
|
||||
|
||||
def test_hkeys(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hkeys("name")
|
||||
|
||||
def test_hlen(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hlen("name")
|
||||
|
||||
def test_hset(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hset("name", "key", 1)
|
||||
|
||||
def test_hsetnx(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hsetnx("name", "key", 2)
|
||||
|
||||
def test_hmset(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hmset("name", {"key": 1})
|
||||
|
||||
def test_hmget(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hmget("name", ["a", "b"])
|
||||
|
||||
def test_hvals(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hvals("name")
|
||||
|
||||
def test_sadd(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sadd("name", 1, 2)
|
||||
|
||||
def test_scard(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.scard("name")
|
||||
|
||||
def test_sdiff(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sdiff(["a", "b"])
|
||||
|
||||
def test_sdiffstore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sdiffstore("dest", ["a", "b"])
|
||||
|
||||
def test_sinter(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sinter(["a", "b"])
|
||||
|
||||
def test_sinterstore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sinterstore("dest", ["a", "b"])
|
||||
|
||||
def test_sismember(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sismember("name", 20)
|
||||
|
||||
def test_smembers(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.smembers("name")
|
||||
|
||||
def test_smove(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.smove("src", "dest", 20)
|
||||
|
||||
def test_spop(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.spop("name")
|
||||
|
||||
def test_srandmember(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.srandmember("name")
|
||||
|
||||
def test_srem(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.srem("name")
|
||||
|
||||
def test_sunion(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sunion(["a", "b"])
|
||||
|
||||
def test_sunionstore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sunionstore("dest", ["a", "b"])
|
||||
|
||||
def test_zadd(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zadd("name", {"key": "value"})
|
||||
|
||||
def test_zcard(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zcard("name")
|
||||
|
||||
def test_zcount(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zcount("name", 1, 5)
|
||||
|
||||
def test_zincrby(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zincrby("name", 1, 1)
|
||||
|
||||
def test_zinterstore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zinterstore("dest", ["a", "b"])
|
||||
|
||||
def test_zrange(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrange("name", 1, 5)
|
||||
|
||||
def test_zrangebyscore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrangebyscore("name", 1, 5)
|
||||
|
||||
def test_rangebylex(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrangebylex("name", 1, 4)
|
||||
|
||||
def test_zrem(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrem("name", "value")
|
||||
|
||||
def test_zremrangebyrank(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zremrangebyrank("name", 1, 5)
|
||||
|
||||
def test_zremrangebyscore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zremrangebyscore("name", 1, 5)
|
||||
|
||||
def test_zremrangebylex(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zremrangebylex("name", 1, 5)
|
||||
|
||||
def test_zlexcount(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zlexcount("name", 1, 5)
|
||||
|
||||
def test_zrevrange(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrevrange("name", 1, 5, 1)
|
||||
|
||||
def test_zrevrangebyscore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrevrangebyscore("name", 5, 1)
|
||||
|
||||
def test_zrevrangebylex(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrevrangebylex("name", 5, 1)
|
||||
|
||||
def test_zrevran(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zrevrank("name", 2)
|
||||
|
||||
def test_zscore(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zscore("name", 2)
|
||||
|
||||
def test_zunionstor(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.zunionstore("dest", ["1", "2"])
|
||||
|
||||
def test_pipeline(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.pipeline().watch("key")
|
||||
|
||||
def test_transaction(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
|
||||
def func(a):
|
||||
return a * a
|
||||
|
||||
r.transaction(func, 3)
|
||||
|
||||
def test_lock(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
with r.lock("name"):
|
||||
pass
|
||||
|
||||
def test_pubsub(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.pubsub().subscribe("channel")
|
||||
|
||||
def test_pfadd(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.pfadd("name", 1)
|
||||
|
||||
def test_pfmerge(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.pfmerge("dest", "a", "b")
|
||||
|
||||
def test_scan(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
list(r.scan())
|
||||
|
||||
def test_sscan(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.sscan("name")
|
||||
|
||||
def test_hscan(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.hscan("name")
|
||||
|
||||
def test_scan_iter(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
list(r.scan_iter())
|
||||
|
||||
def test_sscan_iter(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
list(r.sscan_iter("name"))
|
||||
|
||||
def test_hscan_iter(self, r):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
list(r.hscan_iter("name"))
|
||||
|
||||
|
||||
@pytest.mark.disconnected
|
||||
@testtools.fake_only
|
||||
class TestPubSubConnected:
|
||||
@pytest.fixture
|
||||
def pubsub(self, r):
|
||||
return r.pubsub()
|
||||
|
||||
def test_basic_subscribe(self, pubsub):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
pubsub.subscribe("logs")
|
||||
|
||||
def test_subscription_conn_lost(self, fake_server, pubsub):
|
||||
fake_server.connected = True
|
||||
pubsub.subscribe("logs")
|
||||
fake_server.connected = False
|
||||
# The initial message is already in the pipe
|
||||
msg = pubsub.get_message()
|
||||
check = {"type": "subscribe", "pattern": None, "channel": b"logs", "data": 1}
|
||||
assert msg == check, "Message was not published to channel"
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
pubsub.get_message()
|
|
@ -2,33 +2,22 @@ import functools
|
|||
import math
|
||||
import operator
|
||||
import sys
|
||||
from typing import Tuple, Any
|
||||
from typing import Any, Tuple, Union
|
||||
|
||||
import fakeredis
|
||||
import hypothesis
|
||||
import hypothesis.stateful
|
||||
import hypothesis.strategies as st
|
||||
import pytest
|
||||
import redis
|
||||
from fakeredis._server import _create_version
|
||||
from hypothesis.stateful import rule, initialize, precondition
|
||||
from hypothesis.strategies import SearchStrategy
|
||||
|
||||
import fakeredis
|
||||
from fakeredis._server import _create_version
|
||||
|
||||
self_strategy = st.runner()
|
||||
|
||||
|
||||
def get_redis_version() -> Tuple[int]:
|
||||
try:
|
||||
r = redis.StrictRedis("localhost", port=6380, db=2)
|
||||
r.ping()
|
||||
return _create_version(r.info()["redis_version"])
|
||||
except redis.ConnectionError:
|
||||
return (6,)
|
||||
finally:
|
||||
if hasattr(r, "close"):
|
||||
r.close() # Absent in older versions of redis-py
|
||||
|
||||
|
||||
@st.composite
|
||||
def sample_attr(draw, name):
|
||||
"""Strategy for sampling a specific attribute from a state machine"""
|
||||
|
@ -38,7 +27,28 @@ def sample_attr(draw, name):
|
|||
return values[position]
|
||||
|
||||
|
||||
redis_ver = get_redis_version()
|
||||
def server_info() -> Tuple[str, Union[None, Tuple[int, ...]]]:
|
||||
"""Returns server's version or None if server is not running"""
|
||||
client = None
|
||||
try:
|
||||
client = redis.Redis("localhost", port=6390, db=2)
|
||||
client_info = client.info()
|
||||
server_type = "dragonfly" if "dragonfly_version" in client_info else "redis"
|
||||
server_version = (
|
||||
client_info["redis_version"] if server_type != "dragonfly" else (7, 0)
|
||||
)
|
||||
server_version = _create_version(server_version) or (7,)
|
||||
return server_type, server_version
|
||||
except redis.ConnectionError as e:
|
||||
print(e)
|
||||
pytest.exit("Redis is not running")
|
||||
return "redis", (6,)
|
||||
finally:
|
||||
if hasattr(client, "close"):
|
||||
client.close() # Absent in older versions of redis-py
|
||||
|
||||
|
||||
server_type, redis_ver = server_info()
|
||||
|
||||
keys = sample_attr("keys")
|
||||
fields = sample_attr("fields")
|
||||
|
@ -49,9 +59,7 @@ int_as_bytes = st.builds(lambda x: str(default_normalize(x)).encode(), st.intege
|
|||
float_as_bytes = st.builds(
|
||||
lambda x: repr(default_normalize(x)).encode(), st.floats(width=32)
|
||||
)
|
||||
counts = st.integers(min_value=-3, max_value=3) | st.integers(
|
||||
min_value=-2147483648, max_value=2147483647
|
||||
)
|
||||
counts = st.integers(min_value=-3, max_value=3) | st.integers()
|
||||
limits = st.just(()) | st.tuples(st.just("limit"), counts, counts)
|
||||
# Redis has an integer overflow bug in swapdb, so we confine the numbers to
|
||||
# a limited range (https://github.com/antirez/redis/issues/5737).
|
||||
|
@ -286,7 +294,7 @@ class CommonMachine(hypothesis.stateful.RuleBasedStateMachine):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
try:
|
||||
self.real = redis.StrictRedis("localhost", port=6380, db=2)
|
||||
self.real = redis.StrictRedis("localhost", port=6390, db=2)
|
||||
self.real.ping()
|
||||
except redis.ConnectionError:
|
||||
pytest.skip("redis is not running")
|
||||
|
@ -294,7 +302,7 @@ class CommonMachine(hypothesis.stateful.RuleBasedStateMachine):
|
|||
self.real.connection_pool.disconnect()
|
||||
pytest.skip("redis server is not 64-bit")
|
||||
self.fake = fakeredis.FakeStrictRedis(
|
||||
server=fakeredis.FakeServer(version=redis_ver), port=6380, db=2
|
||||
server=fakeredis.FakeServer(version=redis_ver), port=6390, db=2
|
||||
)
|
||||
# Disable the response parsing so that we can check the raw values returned
|
||||
self.fake.response_callbacks.clear()
|
||||
|
@ -403,15 +411,22 @@ class BaseTest:
|
|||
|
||||
command_strategy: SearchStrategy
|
||||
create_command_strategy = st.nothing()
|
||||
command_strategy_redis7 = st.nothing()
|
||||
|
||||
@pytest.mark.slow
|
||||
def test(self):
|
||||
class Machine(CommonMachine):
|
||||
create_command_strategy = self.create_command_strategy
|
||||
command_strategy = self.command_strategy
|
||||
command_strategy = (
|
||||
self.command_strategy | self.command_strategy_redis7
|
||||
if redis_ver >= (7,)
|
||||
else self.command_strategy
|
||||
)
|
||||
|
||||
# hypothesis.settings.register_profile("debug", max_examples=10, verbosity=hypothesis.Verbosity.debug)
|
||||
# hypothesis.settings.load_profile("debug")
|
||||
hypothesis.settings.register_profile(
|
||||
"debug", max_examples=10, verbosity=hypothesis.Verbosity.debug
|
||||
)
|
||||
hypothesis.settings.load_profile("debug")
|
||||
hypothesis.stateful.run_state_machine_as_test(Machine)
|
||||
|
||||
|
||||
|
@ -420,7 +435,7 @@ class TestConnection(BaseTest):
|
|||
connection_commands = (
|
||||
commands(st.just("echo"), values)
|
||||
| commands(st.just("ping"), st.lists(values, max_size=2))
|
||||
# | commands(st.just("swapdb"), dbnums, dbnums)
|
||||
| commands(st.just("swapdb"), dbnums, dbnums)
|
||||
)
|
||||
command_strategy = connection_commands | common_commands
|
||||
|
||||
|
@ -478,6 +493,50 @@ class TestHash(BaseTest):
|
|||
| commands(st.just("hsetnx"), keys, fields, values)
|
||||
| commands(st.just("hstrlen"), keys, fields)
|
||||
)
|
||||
command_strategy_redis7 = (
|
||||
commands(
|
||||
st.just("hpersist"),
|
||||
st.just("fields"),
|
||||
st.just(2),
|
||||
st.lists(fields, min_size=2, max_size=2),
|
||||
)
|
||||
| commands(
|
||||
st.just("hexpiretime"),
|
||||
st.just("fields"),
|
||||
st.just(2),
|
||||
st.lists(fields, min_size=2, max_size=2),
|
||||
)
|
||||
| commands(
|
||||
st.just("hpexpiretime"),
|
||||
st.just("fields"),
|
||||
st.just(2),
|
||||
st.lists(fields, min_size=2, max_size=2),
|
||||
)
|
||||
| commands(
|
||||
st.just("hexpire"),
|
||||
keys,
|
||||
expires_seconds,
|
||||
st.none() | st.just("nx"),
|
||||
st.none() | st.just("xx"),
|
||||
st.none() | st.just("gt"),
|
||||
st.none() | st.just("lt"),
|
||||
st.just("fields"),
|
||||
st.just(2),
|
||||
st.lists(fields, min_size=2, max_size=2),
|
||||
)
|
||||
| commands(
|
||||
st.just("hpexpire"),
|
||||
keys,
|
||||
expires_ms,
|
||||
st.none() | st.just("nx"),
|
||||
st.none() | st.just("xx"),
|
||||
st.none() | st.just("gt"),
|
||||
st.none() | st.just("lt"),
|
||||
st.just("fields"),
|
||||
st.just(2),
|
||||
st.lists(fields, min_size=2, max_size=2),
|
||||
)
|
||||
)
|
||||
create_command_strategy = commands(
|
||||
st.just("hset"), keys, st.lists(st.tuples(fields, values), min_size=1)
|
||||
)
|
||||
|
@ -499,7 +558,7 @@ class TestList(BaseTest):
|
|||
| commands(
|
||||
st.sampled_from(["lpop", "rpop"]),
|
||||
keys,
|
||||
st.just(None) | st.just([]) | counts,
|
||||
st.just(None) | st.just([]) | st.integers(),
|
||||
)
|
||||
| commands(
|
||||
st.sampled_from(["lpush", "lpushx", "rpush", "rpushx"]),
|
||||
|
@ -781,8 +840,3 @@ def mutated_commands(commands):
|
|||
| add_arg(x, args)
|
||||
| swap_args(x),
|
||||
)
|
||||
|
||||
|
||||
class TestFuzz(BaseTest):
|
||||
command_strategy = mutated_commands(TestJoint.command_strategy)
|
||||
command_strategy = command_strategy.filter(lambda command: command.testable)
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
import fakeredis
|
||||
import pytest
|
||||
|
||||
|
||||
def test_multidb(create_redis):
|
||||
r1 = create_redis(db=2)
|
||||
r2 = create_redis(db=3)
|
||||
|
||||
r1["r1"] = "r1"
|
||||
r2["r2"] = "r2"
|
||||
|
||||
assert "r2" not in r1
|
||||
assert "r1" not in r2
|
||||
|
||||
assert r1["r1"] == b"r1"
|
||||
assert r2["r2"] == b"r2"
|
||||
|
||||
assert r1.flushall() is True
|
||||
|
||||
assert "r1" not in r1
|
||||
assert "r2" not in r2
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
class TestInitArgs:
|
||||
def test_singleton(self):
|
||||
shared_server = fakeredis.FakeServer()
|
||||
r1 = fakeredis.FakeRedis()
|
||||
r2 = fakeredis.FakeRedis(server=fakeredis.FakeServer())
|
||||
r3 = fakeredis.FakeRedis(server=shared_server)
|
||||
r4 = fakeredis.FakeRedis(server=shared_server)
|
||||
|
||||
r1.set("foo", "bar")
|
||||
r3.set("bar", "baz")
|
||||
|
||||
assert "foo" in r1
|
||||
assert "foo" not in r2
|
||||
assert "foo" not in r3
|
||||
|
||||
assert "bar" in r3
|
||||
assert "bar" in r4
|
||||
assert "bar" not in r1
|
||||
|
||||
def test_host_init_arg(self):
|
||||
db = fakeredis.FakeStrictRedis(host="localhost")
|
||||
db.set("foo", "bar")
|
||||
assert db.get("foo") == b"bar"
|
||||
|
||||
def test_from_url(self):
|
||||
db = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/0")
|
||||
db.set("foo", "bar")
|
||||
assert db.get("foo") == b"bar"
|
||||
|
||||
def test_from_url_user(self):
|
||||
db = fakeredis.FakeStrictRedis.from_url("redis://user@localhost:6380/0")
|
||||
db.set("foo", "bar")
|
||||
assert db.get("foo") == b"bar"
|
||||
|
||||
def test_from_url_user_password(self):
|
||||
db = fakeredis.FakeStrictRedis.from_url(
|
||||
"redis://user:password@localhost:6380/0"
|
||||
)
|
||||
db.set("foo", "bar")
|
||||
assert db.get("foo") == b"bar"
|
||||
|
||||
def test_from_url_with_db_arg(self):
|
||||
db = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/0")
|
||||
db1 = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/1")
|
||||
db2 = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/", db=2)
|
||||
db.set("foo", "foo0")
|
||||
db1.set("foo", "foo1")
|
||||
db2.set("foo", "foo2")
|
||||
assert db.get("foo") == b"foo0"
|
||||
assert db1.get("foo") == b"foo1"
|
||||
assert db2.get("foo") == b"foo2"
|
||||
|
||||
def test_from_url_db_value_error(self):
|
||||
# In the case of ValueError, should default to 0, or be absent in redis-py 4.0
|
||||
db = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/a")
|
||||
assert db.connection_pool.connection_kwargs.get("db", 0) == 0
|
||||
|
||||
def test_can_pass_through_extra_args(self):
|
||||
db = fakeredis.FakeStrictRedis.from_url(
|
||||
"redis://localhost:6380/0", decode_responses=True
|
||||
)
|
||||
db.set("foo", "bar")
|
||||
assert db.get("foo") == "bar"
|
||||
|
||||
def test_can_allow_extra_args(self):
|
||||
db = fakeredis.FakeStrictRedis.from_url(
|
||||
"redis://localhost:6380/0",
|
||||
socket_connect_timeout=11,
|
||||
socket_timeout=12,
|
||||
socket_keepalive=True,
|
||||
socket_keepalive_options={60: 30},
|
||||
socket_type=1,
|
||||
retry_on_timeout=True,
|
||||
)
|
||||
fake_conn = db.connection_pool.make_connection()
|
||||
assert fake_conn.socket_connect_timeout == 11
|
||||
assert fake_conn.socket_timeout == 12
|
||||
assert fake_conn.socket_keepalive is True
|
||||
assert fake_conn.socket_keepalive_options == {60: 30}
|
||||
assert fake_conn.socket_type == 1
|
||||
assert fake_conn.retry_on_timeout is True
|
||||
|
||||
# Make fallback logic match redis-py
|
||||
db = fakeredis.FakeStrictRedis.from_url(
|
||||
"redis://localhost:6380/0", socket_connect_timeout=None, socket_timeout=30
|
||||
)
|
||||
fake_conn = db.connection_pool.make_connection()
|
||||
assert fake_conn.socket_connect_timeout == fake_conn.socket_timeout
|
||||
assert fake_conn.socket_keepalive_options == {}
|
||||
|
||||
def test_repr(self):
|
||||
# repr is human-readable, so we only test that it doesn't crash,
|
||||
# and that it contains the db number.
|
||||
db = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/11")
|
||||
rep = repr(db)
|
||||
assert "db=11" in rep
|
||||
|
||||
def test_from_unix_socket(self):
|
||||
db = fakeredis.FakeStrictRedis.from_url("unix://a/b/c")
|
||||
db.set("foo", "bar")
|
||||
assert db.get("foo") == b"bar"
|
||||
|
||||
def test_same_connection_params(self):
|
||||
r1 = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/11")
|
||||
r2 = fakeredis.FakeStrictRedis.from_url("redis://localhost:6380/11")
|
||||
r3 = fakeredis.FakeStrictRedis(server=fakeredis.FakeServer())
|
||||
r1.set("foo", "bar")
|
||||
assert r2.get("foo") == b"bar"
|
||||
assert not r3.exists("foo")
|
||||
|
||||
def test_new_server_with_positional_args(self):
|
||||
from fakeredis import FakeRedis
|
||||
|
||||
# same host, default port and db index
|
||||
fake_redis_1 = FakeRedis("localhost")
|
||||
fake_redis_2 = FakeRedis("localhost")
|
||||
|
||||
fake_redis_1.set("foo", "bar")
|
||||
|
||||
assert fake_redis_2.get("foo") == b"bar"
|
||||
|
||||
# same host and port
|
||||
fake_redis_1 = FakeRedis("localhost", 6000)
|
||||
fake_redis_2 = FakeRedis("localhost", 6000)
|
||||
|
||||
fake_redis_1.set("foo", "bar")
|
||||
|
||||
assert fake_redis_2.get("foo") == b"bar"
|
||||
|
||||
# same connection parameters, but different db index
|
||||
fake_redis_1 = FakeRedis("localhost", 6000, 0)
|
||||
fake_redis_2 = FakeRedis("localhost", 6000, 1)
|
||||
|
||||
fake_redis_1.set("foo", "bar")
|
||||
|
||||
assert fake_redis_2.get("foo") is None
|
||||
|
||||
# mix of positional arguments and keyword args
|
||||
fake_redis_1 = FakeRedis("localhost", port=6000, db=0)
|
||||
fake_redis_2 = FakeRedis("localhost", port=6000, db=1)
|
||||
|
||||
fake_redis_1.set("foo", "bar")
|
||||
|
||||
assert fake_redis_2.get("foo") is None
|
|
@ -1,73 +0,0 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
import redis
|
||||
|
||||
pytestmark = []
|
||||
pytestmark.extend(
|
||||
[
|
||||
pytest.mark.asyncio,
|
||||
]
|
||||
)
|
||||
|
||||
lua_modules_test = pytest.importorskip("lupa")
|
||||
|
||||
|
||||
@pytest.mark.load_lua_modules("cjson")
|
||||
async def test_async_asgi_ratelimit_script(async_redis: redis.Redis):
|
||||
script = """
|
||||
local ruleset = cjson.decode(ARGV[1])
|
||||
|
||||
-- Set limits
|
||||
for i, key in pairs(KEYS) do
|
||||
redis.call('SET', key, ruleset[key][1], 'EX', ruleset[key][2], 'NX')
|
||||
end
|
||||
|
||||
-- Check limits
|
||||
for i = 1, #KEYS do
|
||||
local value = redis.call('GET', KEYS[i])
|
||||
if value and tonumber(value) < 1 then
|
||||
return ruleset[KEYS[i]][2]
|
||||
end
|
||||
end
|
||||
|
||||
-- Decrease limits
|
||||
for i, key in pairs(KEYS) do
|
||||
redis.call('DECR', key)
|
||||
end
|
||||
return 0
|
||||
"""
|
||||
|
||||
script = async_redis.register_script(script)
|
||||
ruleset = {"path:get:user:name": (1, 1)}
|
||||
await script(keys=list(ruleset.keys()), args=[json.dumps(ruleset)])
|
||||
|
||||
|
||||
@pytest.mark.load_lua_modules("cjson")
|
||||
def test_asgi_ratelimit_script(r: redis.Redis):
|
||||
script = """
|
||||
local ruleset = cjson.decode(ARGV[1])
|
||||
|
||||
-- Set limits
|
||||
for i, key in pairs(KEYS) do
|
||||
redis.call('SET', key, ruleset[key][1], 'EX', ruleset[key][2], 'NX')
|
||||
end
|
||||
|
||||
-- Check limits
|
||||
for i = 1, #KEYS do
|
||||
local value = redis.call('GET', KEYS[i])
|
||||
if value and tonumber(value) < 1 then
|
||||
return ruleset[KEYS[i]][2]
|
||||
end
|
||||
end
|
||||
|
||||
-- Decrease limits
|
||||
for i, key in pairs(KEYS) do
|
||||
redis.call('DECR', key)
|
||||
end
|
||||
return 0
|
||||
"""
|
||||
|
||||
script = r.register_script(script)
|
||||
ruleset = {"path:get:user:name": (1, 1)}
|
||||
script(keys=list(ruleset.keys()), args=[json.dumps(ruleset)])
|
|
@ -21,6 +21,19 @@ def test_getbit_wrong_type(r: redis.Redis):
|
|||
r.getbit("foo", 1)
|
||||
|
||||
|
||||
@pytest.mark.min_server("7")
|
||||
def test_bitcount_error(r: redis.Redis):
|
||||
with pytest.raises(redis.ResponseError) as e:
|
||||
raw_command(r, b"BITCOUNT", b"", b"", b"")
|
||||
assert str(e.value) == "value is not an integer or out of range"
|
||||
|
||||
|
||||
@pytest.mark.min_server("7")
|
||||
def test_bitcount_does_not_exist(r: redis.Redis):
|
||||
res = raw_command(r, b"BITCOUNT", b"", 0, 0)
|
||||
assert res == 0
|
||||
|
||||
|
||||
def test_multiple_bits_set(r: redis.Redis):
|
||||
r.setbit("foo", 1, 1)
|
||||
r.setbit("foo", 3, 1)
|
||||
|
@ -373,10 +386,7 @@ def test_bitfield_incr_sat(r: redis.Redis):
|
|||
r.set(key, b"\xff\xf0\x00")
|
||||
assert r.bitfield(key, "SAT").incrby("u8", 4, 0x123).incrby(
|
||||
"u8", 8, 0x55
|
||||
).execute() == [
|
||||
0xFF,
|
||||
0xFF,
|
||||
]
|
||||
).execute() == [0xFF, 0xFF]
|
||||
assert r.get(key) == b"\xff\xff\x00"
|
||||
assert r.bitfield(key, "SAT").incrby("u12", 0, -1).incrby("u1", 1, 2).execute() == [
|
||||
0xFFE,
|
||||
|
@ -406,17 +416,11 @@ def test_bitfield_incr_fail(r: redis.Redis):
|
|||
r.set(key, b"\xff\xf0\x00")
|
||||
assert r.bitfield(key, "FAIL").incrby("u8", 4, 0x123).incrby(
|
||||
"u8", 8, 0x55
|
||||
).execute() == [
|
||||
None,
|
||||
None,
|
||||
]
|
||||
).execute() == [None, None]
|
||||
assert r.get(key) == b"\xff\xf0\x00"
|
||||
assert r.bitfield(key, "FAIL").incrby("u12", 0, -1).incrby(
|
||||
"u1", 1, 2
|
||||
).execute() == [
|
||||
0xFFE,
|
||||
None,
|
||||
]
|
||||
).execute() == [0xFFE, None]
|
||||
assert r.get(key) == b"\xff\xe0\x00"
|
||||
assert r.bitfield(key, "FAIL").incrby("i4", 0, 8).incrby("i4", 4, 7).execute() == [
|
||||
7,
|
||||
|
|
52
tests/fakeredis/test/test_mixins/test_connection.py
Normal file
52
tests/fakeredis/test/test_mixins/test_connection.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
import pytest
|
||||
import redis
|
||||
import redis.client
|
||||
from fakeredis import _msgs as msgs
|
||||
from redis.exceptions import ResponseError
|
||||
|
||||
from test import testtools
|
||||
from test.testtools import raw_command
|
||||
|
||||
|
||||
def test_ping(r: redis.Redis):
|
||||
assert r.ping()
|
||||
assert testtools.raw_command(r, "ping", "test") == b"test"
|
||||
with pytest.raises(
|
||||
redis.ResponseError, match=msgs.WRONG_ARGS_MSG6.format("ping")[4:]
|
||||
):
|
||||
raw_command(r, "ping", "arg1", "arg2")
|
||||
|
||||
|
||||
def test_echo(r: redis.Redis):
|
||||
assert r.echo(b"hello") == b"hello"
|
||||
assert r.echo("hello") == b"hello"
|
||||
|
||||
|
||||
def test_unknown_command(r: redis.Redis):
|
||||
with pytest.raises(redis.ResponseError):
|
||||
raw_command(r, "0 3 3")
|
||||
|
||||
|
||||
@pytest.mark.decode_responses
|
||||
class TestDecodeResponses:
|
||||
def test_decode_str(self, r):
|
||||
r.set("foo", "bar")
|
||||
assert r.get("foo") == "bar"
|
||||
|
||||
def test_decode_set(self, r):
|
||||
r.sadd("foo", "member1")
|
||||
assert set(r.smembers("foo")) == {"member1"}
|
||||
|
||||
def test_decode_list(self, r):
|
||||
r.rpush("foo", "a", "b")
|
||||
assert r.lrange("foo", 0, -1) == ["a", "b"]
|
||||
|
||||
def test_decode_dict(self, r):
|
||||
r.hset("foo", "key", "value")
|
||||
assert r.hgetall("foo") == {"key": "value"}
|
||||
|
||||
def test_decode_error(self, r):
|
||||
r.set("foo", "bar")
|
||||
with pytest.raises(ResponseError) as exc_info:
|
||||
r.hset("foo", "bar", "baz")
|
||||
assert isinstance(exc_info.value.args[0], str)
|
|
@ -5,6 +5,7 @@ import pytest
|
|||
import redis
|
||||
from fakeredis import _msgs as msgs
|
||||
from redis.exceptions import ResponseError
|
||||
|
||||
from test.testtools import raw_command
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from test import testtools
|
||||
from typing import Dict, Any
|
||||
|
||||
import pytest
|
||||
import redis
|
||||
|
||||
from test import testtools
|
||||
|
||||
|
||||
def test_geoadd_ch(r: redis.Redis):
|
||||
values = (2.1909389952632, 41.433791470673, "place1")
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from test import testtools
|
||||
|
||||
import pytest
|
||||
import redis
|
||||
import redis.client
|
||||
|
||||
from test import testtools
|
||||
|
||||
|
||||
def test_hstrlen_missing(r: redis.Redis):
|
||||
assert r.hstrlen("foo", "doesnotexist") == 0
|
||||
|
|
|
@ -616,13 +616,6 @@ def test_blmove(r: redis.Redis):
|
|||
assert r.blmove("a", "b", 1, "RIGHT", "LEFT")
|
||||
|
||||
|
||||
@pytest.mark.disconnected
|
||||
@testtools.fake_only
|
||||
def test_lmove_disconnected_raises_connection_error(r: redis.Redis):
|
||||
with pytest.raises(redis.ConnectionError):
|
||||
r.lmove(1, 2, "LEFT", "RIGHT")
|
||||
|
||||
|
||||
def test_lpos(r: redis.Redis):
|
||||
assert r.rpush("a", "a", "b", "c", "1", "2", "3", "c", "c") == 8
|
||||
assert r.lpos("a", "a") == 0
|
||||
|
|
|
@ -5,7 +5,6 @@ from queue import Queue
|
|||
from time import sleep
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
import fakeredis
|
||||
import pytest
|
||||
import redis
|
||||
from redis.client import PubSub
|
||||
|
@ -363,17 +362,6 @@ def test_pubsub_timeout(r, timeout_value):
|
|||
assert message is None
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
def test_socket_cleanup_pubsub(fake_server):
|
||||
r1 = fakeredis.FakeStrictRedis(server=fake_server)
|
||||
r2 = fakeredis.FakeStrictRedis(server=fake_server)
|
||||
ps = r1.pubsub()
|
||||
with ps:
|
||||
ps.subscribe("test")
|
||||
ps.psubscribe("test*")
|
||||
r2.publish("test", "foo")
|
||||
|
||||
|
||||
def test_pubsub_channels(r: redis.Redis):
|
||||
p = r.pubsub()
|
||||
p.subscribe("foo", "bar", "baz", "test")
|
||||
|
|
|
@ -2,6 +2,7 @@ from time import sleep
|
|||
|
||||
import pytest
|
||||
import redis
|
||||
|
||||
from test.testtools import key_val_dict
|
||||
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from test import testtools
|
||||
|
||||
import fakeredis
|
||||
import pytest
|
||||
import redis
|
||||
import redis.client
|
||||
from redis.exceptions import ResponseError
|
||||
|
||||
from test.testtools import raw_command
|
||||
|
||||
json_tests = pytest.importorskip("lupa")
|
||||
|
@ -552,26 +549,6 @@ def test_script(r: redis.Redis):
|
|||
assert result == b"42"
|
||||
|
||||
|
||||
@testtools.fake_only
|
||||
def test_lua_log(r, caplog):
|
||||
logger = fakeredis._server.LOGGER
|
||||
script = """
|
||||
redis.log(redis.LOG_DEBUG, "debug")
|
||||
redis.log(redis.LOG_VERBOSE, "verbose")
|
||||
redis.log(redis.LOG_NOTICE, "notice")
|
||||
redis.log(redis.LOG_WARNING, "warning")
|
||||
"""
|
||||
script = r.register_script(script)
|
||||
with caplog.at_level("DEBUG"):
|
||||
script()
|
||||
assert caplog.record_tuples == [
|
||||
(logger.name, logging.DEBUG, "debug"),
|
||||
(logger.name, logging.INFO, "verbose"),
|
||||
(logger.name, logging.INFO, "notice"),
|
||||
(logger.name, logging.WARNING, "warning"),
|
||||
]
|
||||
|
||||
|
||||
def test_lua_log_no_message(r: redis.Redis):
|
||||
script = "redis.log(redis.LOG_DEBUG)"
|
||||
script = r.register_script(script)
|
||||
|
@ -579,18 +556,6 @@ def test_lua_log_no_message(r: redis.Redis):
|
|||
script()
|
||||
|
||||
|
||||
@testtools.fake_only
|
||||
def test_lua_log_different_types(r, caplog):
|
||||
logger = logging.getLogger("fakeredis")
|
||||
script = "redis.log(redis.LOG_DEBUG, 'string', 1, true, 3.14, 'string')"
|
||||
script = r.register_script(script)
|
||||
with caplog.at_level("DEBUG"):
|
||||
script()
|
||||
assert caplog.record_tuples == [
|
||||
(logger.name, logging.DEBUG, "string 1 3.14 string")
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_lua_log_wrong_level(r: redis.Redis):
|
||||
script = "redis.log(10, 'string')"
|
||||
|
@ -599,19 +564,6 @@ def test_lua_log_wrong_level(r: redis.Redis):
|
|||
script()
|
||||
|
||||
|
||||
@testtools.fake_only
|
||||
def test_lua_log_defined_vars(r, caplog):
|
||||
logger = fakeredis._server.LOGGER
|
||||
script = """
|
||||
local var='string'
|
||||
redis.log(redis.LOG_DEBUG, var)
|
||||
"""
|
||||
script = r.register_script(script)
|
||||
with caplog.at_level("DEBUG"):
|
||||
script()
|
||||
assert caplog.record_tuples == [(logger.name, logging.DEBUG, "string")]
|
||||
|
||||
|
||||
def test_hscan_cursors_are_bytes(r: redis.Redis):
|
||||
r.hset("hkey", "foo", 1)
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ from time import sleep
|
|||
|
||||
import pytest
|
||||
import redis
|
||||
from fakeredis._commands import SUPPORTED_COMMANDS
|
||||
from redis.exceptions import ResponseError
|
||||
from test.testtools import fake_only
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
|
@ -46,20 +44,6 @@ def test_lastsave(r: redis.Redis):
|
|||
assert isinstance(r.lastsave(), datetime)
|
||||
|
||||
|
||||
@fake_only
|
||||
def test_command(r: redis.Redis):
|
||||
commands_dict = r.command()
|
||||
one_word_commands = {cmd for cmd in SUPPORTED_COMMANDS if " " not in cmd}
|
||||
assert one_word_commands - set(commands_dict.keys()) == set()
|
||||
|
||||
|
||||
@fake_only
|
||||
def test_command_count(r: redis.Redis):
|
||||
assert r.command_count() >= len(
|
||||
[cmd for cmd in SUPPORTED_COMMANDS if " " not in cmd]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
@pytest.mark.slow
|
||||
def test_bgsave_timestamp_update(r: redis.Redis):
|
||||
|
|
|
@ -2,13 +2,14 @@ from __future__ import annotations
|
|||
|
||||
import math
|
||||
from collections import OrderedDict
|
||||
from test import testtools
|
||||
from typing import Tuple, List, Optional
|
||||
|
||||
import pytest
|
||||
import redis
|
||||
import redis.client
|
||||
|
||||
from test import testtools
|
||||
|
||||
|
||||
def round_str(x):
|
||||
assert isinstance(x, bytes)
|
|
@ -1,12 +1,12 @@
|
|||
import threading
|
||||
import time
|
||||
from test import testtools
|
||||
from typing import List
|
||||
|
||||
import pytest
|
||||
import redis
|
||||
from fakeredis import _msgs as msgs
|
||||
from fakeredis._stream import XStream, StreamRangeTest
|
||||
|
||||
from test import testtools
|
||||
|
||||
|
||||
def get_ids(results):
|
||||
|
@ -20,49 +20,6 @@ def add_items(r: redis.Redis, stream: str, n: int):
|
|||
return id_list
|
||||
|
||||
|
||||
@pytest.mark.fake
|
||||
def test_xstream():
|
||||
stream = XStream()
|
||||
stream.add([0, 0, 1, 1, 2, 2, 3, 3], "0-1")
|
||||
stream.add([1, 1, 2, 2, 3, 3, 4, 4], "1-2")
|
||||
stream.add([2, 2, 3, 3, 4, 4], "1-3")
|
||||
stream.add([3, 3, 4, 4], "2-1")
|
||||
stream.add([3, 3, 4, 4], "2-2")
|
||||
stream.add([3, 3, 4, 4], "3-1")
|
||||
assert stream.add([3, 3, 4, 4], "4-*") == b"4-0"
|
||||
assert stream.last_item_key() == b"4-0"
|
||||
assert stream.add([3, 3, 4, 4], "4-*-*") is None
|
||||
assert len(stream) == 7
|
||||
i = iter(stream)
|
||||
assert next(i) == [b"0-1", [0, 0, 1, 1, 2, 2, 3, 3]]
|
||||
assert next(i) == [b"1-2", [1, 1, 2, 2, 3, 3, 4, 4]]
|
||||
assert next(i) == [b"1-3", [2, 2, 3, 3, 4, 4]]
|
||||
assert next(i) == [b"2-1", [3, 3, 4, 4]]
|
||||
assert next(i) == [b"2-2", [3, 3, 4, 4]]
|
||||
|
||||
assert stream.find_index_key_as_str("1-2") == (1, True)
|
||||
assert stream.find_index_key_as_str("0-1") == (0, True)
|
||||
assert stream.find_index_key_as_str("2-1") == (3, True)
|
||||
assert stream.find_index_key_as_str("1-4") == (3, False)
|
||||
|
||||
lst = stream.irange(StreamRangeTest.decode(b"0-2"), StreamRangeTest.decode(b"3-0"))
|
||||
assert len(lst) == 4
|
||||
|
||||
stream = XStream()
|
||||
assert stream.delete(["1"]) == 0
|
||||
entry_key: bytes = stream.add([0, 0, 1, 1, 2, 2, 3, 3])
|
||||
assert len(stream) == 1
|
||||
assert (
|
||||
stream.delete(
|
||||
[
|
||||
entry_key,
|
||||
]
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert len(stream) == 0
|
||||
|
||||
|
||||
def test_xadd_redis__green(r: redis.Redis):
|
||||
stream = "stream"
|
||||
before = int(1000 * time.time())
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
import pytest
|
||||
import redis.commands.bf
|
||||
from redis.commands.bf import BFInfo
|
||||
|
||||
json_tests = pytest.importorskip("probables")
|
||||
|
||||
|
||||
def intlist(obj):
|
||||
return [int(v) for v in obj]
|
||||
|
||||
|
||||
def test_create_bf(r: redis.Redis):
|
||||
"""Test CREATE/RESERVE calls"""
|
||||
assert r.bf().create("bloom", 0.01, 1000)
|
||||
assert r.bf().create("bloom_e", 0.01, 1000, expansion=1)
|
||||
assert r.bf().create("bloom_ns", 0.01, 1000, noScale=True)
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_create_cf(r: redis.Redis):
|
||||
assert r.cf().create("cuckoo", 1000)
|
||||
assert r.cf().create("cuckoo_e", 1000, expansion=1)
|
||||
assert r.cf().create("cuckoo_bs", 1000, bucket_size=4)
|
||||
assert r.cf().create("cuckoo_mi", 1000, max_iterations=10)
|
||||
assert r.cms().initbydim("cmsDim", 100, 5)
|
||||
assert r.cms().initbyprob("cmsProb", 0.01, 0.01)
|
||||
assert r.topk().reserve("topk", 5, 100, 5, 0.9)
|
||||
|
||||
|
||||
def test_bf_reserve(r: redis.Redis):
|
||||
"""Testing BF.RESERVE"""
|
||||
assert r.bf().reserve("bloom", 0.01, 1000)
|
||||
assert r.bf().reserve("bloom_e", 0.01, 1000, expansion=1)
|
||||
assert r.bf().reserve("bloom_ns", 0.01, 1000, noScale=True)
|
||||
|
||||
|
||||
def test_bf_add(r: redis.Redis):
|
||||
assert r.bf().create("bloom", 0.01, 1000)
|
||||
assert 1 == r.bf().add("bloom", "foo")
|
||||
assert 0 == r.bf().add("bloom", "foo")
|
||||
assert [0] == intlist(r.bf().madd("bloom", "foo"))
|
||||
assert [0, 1] == r.bf().madd("bloom", "foo", "bar")
|
||||
assert [0, 0, 1] == r.bf().madd("bloom", "foo", "bar", "baz")
|
||||
assert 1 == r.bf().exists("bloom", "foo")
|
||||
assert 0 == r.bf().exists("bloom", "noexist")
|
||||
assert [1, 0] == intlist(r.bf().mexists("bloom", "foo", "noexist"))
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_insert(r: redis.Redis):
|
||||
assert r.bf().create("bloom", 0.01, 1000)
|
||||
assert [1] == intlist(r.bf().insert("bloom", ["foo"]))
|
||||
assert [0, 1] == intlist(r.bf().insert("bloom", ["foo", "bar"]))
|
||||
assert [1] == intlist(r.bf().insert("captest", ["foo"], capacity=10))
|
||||
assert [1] == intlist(r.bf().insert("errtest", ["foo"], error=0.01))
|
||||
assert 1 == r.bf().exists("bloom", "foo")
|
||||
assert 0 == r.bf().exists("bloom", "noexist")
|
||||
assert [1, 0] == intlist(r.bf().mexists("bloom", "foo", "noexist"))
|
||||
info = r.bf().info("bloom")
|
||||
assert 2 == info.get("insertedNum")
|
||||
assert 1000 == info.get("capacity")
|
||||
assert 1 == info.get("filterNum")
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_scandump_and_loadchunk(r: redis.Redis):
|
||||
r.bf().create("myBloom", "0.0001", "1000")
|
||||
|
||||
# Test is probabilistic and might fail. It is OK to change variables if
|
||||
# certain to not break anything
|
||||
|
||||
res = 0
|
||||
for x in range(1000):
|
||||
r.bf().add("myBloom", x)
|
||||
assert r.bf().exists("myBloom", x)
|
||||
rv = r.bf().exists("myBloom", f"nonexist_{x}")
|
||||
res += rv == x
|
||||
assert res < 5
|
||||
|
||||
cmds = list()
|
||||
first = 0
|
||||
while first is not None:
|
||||
cur = r.bf().scandump("myBloom", first)
|
||||
if cur[0] == 0:
|
||||
first = None
|
||||
else:
|
||||
first = cur[0]
|
||||
cmds.append(cur)
|
||||
|
||||
# Remove the filter
|
||||
r.bf().client.delete("myBloom")
|
||||
|
||||
# Now, load all the commands:
|
||||
for cmd in cmds:
|
||||
r.bf().loadchunk("myBloom1", *cmd)
|
||||
|
||||
for x in range(1000):
|
||||
assert r.bf().exists("myBloom1", x), f"{x} not in filter"
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_info(r: redis.Redis):
|
||||
# Store a filter
|
||||
r.bf().create("nonscaling", "0.0001", "1000", noScale=True)
|
||||
info: BFInfo = r.bf().info("nonscaling")
|
||||
assert info.expansionRate is None
|
||||
|
||||
expansion = 4
|
||||
r.bf().create("expanding", "0.0001", "1000", expansion=expansion)
|
||||
info = r.bf().info("expanding")
|
||||
assert info.expansionRate == 4
|
||||
assert info.capacity == 1000
|
||||
assert info.insertedNum == 0
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_card(r: redis.Redis):
|
||||
# return 0 if the key does not exist
|
||||
assert r.bf().card("not_exist") == 0
|
||||
|
||||
# Store a filter
|
||||
assert r.bf().add("bf1", "item_foo") == 1
|
||||
assert r.bf().card("bf1") == 1
|
||||
|
||||
# Error when key is of a type other than Bloom filter.
|
||||
with pytest.raises(redis.ResponseError):
|
||||
r.set("setKey", "value")
|
||||
r.bf().card("setKey")
|
|
@ -1,11 +1,44 @@
|
|||
import pytest
|
||||
import redis
|
||||
from redis.commands.bf import BFInfo
|
||||
|
||||
from fakeredis import _msgs as msgs
|
||||
|
||||
bloom_tests = pytest.importorskip("probables")
|
||||
|
||||
|
||||
def intlist(obj):
|
||||
return [int(v) for v in obj]
|
||||
|
||||
|
||||
def test_create_bf(r: redis.Redis):
|
||||
assert r.bf().create("bloom", 0.01, 1000)
|
||||
assert r.bf().create("bloom_e", 0.01, 1000, expansion=1)
|
||||
assert r.bf().create("bloom_ns", 0.01, 1000, noScale=True)
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_create_cf(r: redis.Redis):
|
||||
assert r.cf().create("cuckoo", 1000)
|
||||
assert r.cf().create("cuckoo_e", 1000, expansion=1)
|
||||
assert r.cf().create("cuckoo_bs", 1000, bucket_size=4)
|
||||
assert r.cf().create("cuckoo_mi", 1000, max_iterations=10)
|
||||
assert r.cms().initbydim("cmsDim", 100, 5)
|
||||
assert r.cms().initbyprob("cmsProb", 0.01, 0.01)
|
||||
assert r.topk().reserve("topk", 5, 100, 5, 0.9)
|
||||
|
||||
|
||||
def test_bf_reserve(r: redis.Redis):
|
||||
assert r.bf().reserve("bloom", 0.01, 1000)
|
||||
assert r.bf().reserve("bloom_ns", 0.01, 1000, noScale=True)
|
||||
with pytest.raises(
|
||||
redis.exceptions.ResponseError, match=msgs.NONSCALING_FILTERS_CANNOT_EXPAND_MSG
|
||||
):
|
||||
assert r.bf().reserve("bloom_e", 0.01, 1000, expansion=1, noScale=True)
|
||||
with pytest.raises(redis.exceptions.ResponseError, match=msgs.ITEM_EXISTS_MSG):
|
||||
assert r.bf().reserve("bloom", 0.01, 1000)
|
||||
|
||||
|
||||
def test_bf_add(r: redis.Redis):
|
||||
assert r.bf().add("key", "value") == 1
|
||||
assert r.bf().add("key", "value") == 0
|
||||
|
@ -13,6 +46,15 @@ def test_bf_add(r: redis.Redis):
|
|||
r.set("key1", "value")
|
||||
with pytest.raises(redis.exceptions.ResponseError):
|
||||
r.bf().add("key1", "v")
|
||||
assert r.bf().create("bloom", 0.01, 1000)
|
||||
assert 1 == r.bf().add("bloom", "foo")
|
||||
assert 0 == r.bf().add("bloom", "foo")
|
||||
assert [0] == intlist(r.bf().madd("bloom", "foo"))
|
||||
assert [0, 1] == r.bf().madd("bloom", "foo", "bar")
|
||||
assert [0, 0, 1] == r.bf().madd("bloom", "foo", "bar", "baz")
|
||||
assert 1 == r.bf().exists("bloom", "foo")
|
||||
assert 0 == r.bf().exists("bloom", "noexist")
|
||||
assert [1, 0] == intlist(r.bf().mexists("bloom", "foo", "noexist"))
|
||||
|
||||
|
||||
def test_bf_madd(r: redis.Redis):
|
||||
|
@ -33,6 +75,17 @@ def test_bf_card(r: redis.Redis):
|
|||
r.set("key1", "value")
|
||||
with pytest.raises(redis.exceptions.ResponseError):
|
||||
r.bf().card("key1")
|
||||
# return 0 if the key does not exist
|
||||
assert r.bf().card("not_exist") == 0
|
||||
|
||||
# Store a filter
|
||||
assert r.bf().add("bf1", "item_foo") == 1
|
||||
assert r.bf().card("bf1") == 1
|
||||
|
||||
# Error when key is of a type other than Bloom filter.
|
||||
with pytest.raises(redis.ResponseError):
|
||||
r.set("setKey", "value")
|
||||
r.bf().card("setKey")
|
||||
|
||||
|
||||
def test_bf_exists(r: redis.Redis):
|
||||
|
@ -61,29 +114,78 @@ def test_bf_mexists(r: redis.Redis):
|
|||
r.bf().add("key1", "v")
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_reserve(r: redis.Redis):
|
||||
assert r.bf().reserve("bloom", 0.01, 1000)
|
||||
assert r.bf().reserve("bloom_ns", 0.01, 1000, noScale=True)
|
||||
with pytest.raises(
|
||||
redis.exceptions.ResponseError, match=msgs.NONSCALING_FILTERS_CANNOT_EXPAND_MSG
|
||||
):
|
||||
assert r.bf().reserve("bloom_e", 0.01, 1000, expansion=1, noScale=True)
|
||||
with pytest.raises(redis.exceptions.ResponseError, match=msgs.ITEM_EXISTS_MSG):
|
||||
assert r.bf().reserve("bloom", 0.01, 1000)
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_insert(r: redis.Redis):
|
||||
assert r.bf().create("bloom", 0.01, 1000)
|
||||
assert r.bf().insert("bloom", ["foo"]) == [1]
|
||||
assert r.bf().insert("bloom", ["foo", "bar"]) == [0, 1]
|
||||
assert r.bf().create("key", 0.01, 1000)
|
||||
assert r.bf().insert("key", ["foo"]) == [1]
|
||||
assert r.bf().insert("key", ["foo", "bar"]) == [0, 1]
|
||||
assert r.bf().insert("captest", ["foo"], capacity=10) == [1]
|
||||
assert r.bf().insert("errtest", ["foo"], error=0.01) == [1]
|
||||
assert r.bf().exists("bloom", "foo") == 1
|
||||
assert r.bf().exists("bloom", "noexist") == 0
|
||||
assert r.bf().mexists("bloom", "foo", "noexist") == [1, 0]
|
||||
assert r.bf().exists("key", "foo") == 1
|
||||
assert r.bf().exists("key", "noexist") == 0
|
||||
assert r.bf().mexists("key", "foo", "noexist") == [1, 0]
|
||||
with pytest.raises(redis.exceptions.ResponseError, match=msgs.NOT_FOUND_MSG):
|
||||
r.bf().insert("nocreate", [1, 2, 3], noCreate=True)
|
||||
# with pytest.raises(redis.exceptions.ResponseError, match=msgs.NONSCALING_FILTERS_CANNOT_EXPAND_MSG):
|
||||
# r.bf().insert("nocreate", [1, 2, 3], expansion=2, noScale=True)
|
||||
assert r.bf().create("bloom", 0.01, 1000)
|
||||
assert [1] == intlist(r.bf().insert("bloom", ["foo"]))
|
||||
assert [0, 1] == intlist(r.bf().insert("bloom", ["foo", "bar"]))
|
||||
assert 1 == r.bf().exists("bloom", "foo")
|
||||
assert 0 == r.bf().exists("bloom", "noexist")
|
||||
assert [1, 0] == intlist(r.bf().mexists("bloom", "foo", "noexist"))
|
||||
info = r.bf().info("bloom")
|
||||
assert 2 == info.get("insertedNum")
|
||||
assert 1000 == info.get("capacity")
|
||||
assert 1 == info.get("filterNum")
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_scandump_and_loadchunk(r: redis.Redis):
|
||||
r.bf().create("myBloom", "0.0001", "1000")
|
||||
|
||||
# Test is probabilistic and might fail. It is OK to change variables if
|
||||
# certain to not break anything
|
||||
|
||||
res = 0
|
||||
for x in range(1000):
|
||||
r.bf().add("myBloom", x)
|
||||
assert r.bf().exists("myBloom", x)
|
||||
rv = r.bf().exists("myBloom", f"nonexist_{x}")
|
||||
res += rv == x
|
||||
assert res < 5
|
||||
|
||||
cmds = list()
|
||||
first = 0
|
||||
while first is not None:
|
||||
cur = r.bf().scandump("myBloom", first)
|
||||
if cur[0] == 0:
|
||||
first = None
|
||||
else:
|
||||
first = cur[0]
|
||||
cmds.append(cur)
|
||||
|
||||
# Remove the filter
|
||||
r.bf().client.delete("myBloom")
|
||||
|
||||
# Now, load all the commands:
|
||||
for cmd in cmds:
|
||||
r.bf().loadchunk("myBloom1", *cmd)
|
||||
|
||||
for x in range(1000):
|
||||
assert r.bf().exists("myBloom1", x), f"{x} not in filter"
|
||||
|
||||
|
||||
@pytest.mark.unsupported_server_types("dragonfly")
|
||||
def test_bf_info(r: redis.Redis):
|
||||
# Store a filter
|
||||
r.bf().create("nonscaling", "0.0001", "1000", noScale=True)
|
||||
info: BFInfo = r.bf().info("nonscaling")
|
||||
assert info.expansionRate is None
|
||||
|
||||
expansion = 4
|
||||
r.bf().create("expanding", "0.0001", "1000", expansion=expansion)
|
||||
info = r.bf().info("expanding")
|
||||
assert info.expansionRate == 4
|
||||
assert info.capacity == 1000
|
||||
assert info.insertedNum == 0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue