dragonfly/tests/fakeredis/test/test_mixins/test_scan.py
Daniel M 1958e09a9a
refactor: refactor fakeredis tests (#3852)
* refactor:fakeredis tests
2024-10-03 12:41:05 +03:00

206 lines
6.2 KiB
Python

from time import sleep
import pytest
import redis
from test.testtools import key_val_dict
def test_sscan_delete_key_while_scanning_should_not_returns_it_in_scan(r: redis.Redis):
size = 600
name = "sscan-test"
all_keys_set = {f"{i}".encode() for i in range(size)}
r.sadd(name, *[k for k in all_keys_set])
assert r.scard(name) == size
cursor, keys = r.sscan(name, 0)
assert len(keys) < len(all_keys_set)
key_to_remove = next(x for x in all_keys_set if x not in keys)
assert r.srem(name, key_to_remove) == 1
assert not r.sismember(name, key_to_remove)
while cursor != 0:
cursor, data = r.sscan(name, cursor=cursor)
keys.extend(data)
assert len(set(keys)) == len(keys)
assert len(keys) == size - 1
assert key_to_remove not in keys
def test_hscan_delete_key_while_scanning_should_not_returns_it_in_scan(r: redis.Redis):
size = 600
name = "hscan-test"
all_keys_dict = key_val_dict(size=size)
r.hset(name, mapping=all_keys_dict)
assert len(r.hgetall(name)) == size
cursor, keys = r.hscan(name, 0)
assert len(keys) < len(all_keys_dict)
key_to_remove = next(x for x in all_keys_dict if x not in keys)
assert r.hdel(name, key_to_remove) == 1
assert r.hget(name, key_to_remove) is None
while cursor != 0:
cursor, data = r.hscan(name, cursor=cursor)
keys.update(data)
assert len(set(keys)) == len(keys)
assert len(keys) == size - 1
assert key_to_remove not in keys
def test_scan_delete_unseen_key_while_scanning_should_not_returns_it_in_scan(
r: redis.Redis,
):
size = 30
all_keys_dict = key_val_dict(size=size)
assert all(r.set(k, v) for k, v in all_keys_dict.items())
assert len(r.keys()) == size
cursor, keys = r.scan()
key_to_remove = next(x for x in all_keys_dict if x not in keys)
assert r.delete(key_to_remove) == 1
assert r.get(key_to_remove) is None
while cursor != 0:
cursor, data = r.scan(cursor=cursor)
keys.extend(data)
assert len(set(keys)) == len(keys)
assert len(keys) == size - 1
assert key_to_remove not in keys
# @pytest.mark.xfail # todo
# def test_scan_delete_seen_key_while_scanning_should_return_all_keys(r: redis.Redis):
# size = 30
# all_keys_dict = key_val_dict(size=size)
# assert all(r.set(k, v) for k, v in all_keys_dict.items())
# assert len(r.keys()) == size
#
# cursor, keys = r.scan()
#
# key_to_remove = keys[0]
# assert r.delete(keys[0]) == 1
# assert r.get(key_to_remove) is None
# while cursor != 0:
# cursor, data = r.scan(cursor=cursor)
# keys.extend(data)
#
# assert len(set(keys)) == len(keys)
# keys = set(keys)
# assert len(keys) == size, f"{set(all_keys_dict).difference(keys)} is not empty but should be"
# assert key_to_remove in keys
def test_scan_add_key_while_scanning_should_return_all_keys(r: redis.Redis):
size = 30
all_keys_dict = key_val_dict(size=size)
assert all(r.set(k, v) for k, v in all_keys_dict.items())
assert len(r.keys()) == size
cursor, keys = r.scan()
r.set("new_key", "new val")
while cursor != 0:
cursor, data = r.scan(cursor=cursor)
keys.extend(data)
keys = set(keys)
assert (
len(keys) >= size
), f"{set(all_keys_dict).difference(keys)} is not empty but should be"
def test_scan(r: redis.Redis):
# Set up the data
for ix in range(20):
k = "scan-test:%s" % ix
v = "result:%s" % ix
r.set(k, v)
expected = r.keys()
assert len(expected) == 20 # Ensure we know what we're testing
# Test that we page through the results and get everything out
results = []
cursor = "0"
while cursor != 0:
cursor, data = r.scan(cursor, count=6)
results.extend(data)
assert set(expected) == set(results)
# Now test that the MATCH functionality works
results = []
cursor = "0"
while cursor != 0:
cursor, data = r.scan(cursor, match="*7", count=100)
results.extend(data)
assert b"scan-test:7" in results
assert b"scan-test:17" in results
assert len(set(results)) == 2
# Test the match on iterator
results = [r for r in r.scan_iter(match="*7")]
assert b"scan-test:7" in results
assert b"scan-test:17" in results
assert len(set(results)) == 2
def test_scan_single(r: redis.Redis):
r.set("foo1", "bar1")
assert r.scan(match="foo*") == (0, [b"foo1"])
def test_scan_iter_single_page(r: redis.Redis):
r.set("foo1", "bar1")
r.set("foo2", "bar2")
assert set(r.scan_iter(match="foo*")) == {b"foo1", b"foo2"}
assert set(r.scan_iter()) == {b"foo1", b"foo2"}
assert set(r.scan_iter(match="")) == set()
assert set(r.scan_iter(match="foo1", _type="string")) == {
b"foo1",
}
def test_scan_iter_multiple_pages(r: redis.Redis):
all_keys = key_val_dict(size=100)
assert all(r.set(k, v) for k, v in all_keys.items())
assert set(r.scan_iter()) == set(all_keys)
def test_scan_iter_multiple_pages_with_match(r: redis.Redis):
all_keys = key_val_dict(size=100)
assert all(r.set(k, v) for k, v in all_keys.items())
# Now add a few keys that don't match the key:<number> pattern.
r.set("otherkey", "foo")
r.set("andanother", "bar")
actual = set(r.scan_iter(match="key:*"))
assert actual == set(all_keys)
def test_scan_multiple_pages_with_count_arg(r: redis.Redis):
all_keys = key_val_dict(size=100)
assert all(r.set(k, v) for k, v in all_keys.items())
assert set(r.scan_iter(count=1000)) == set(all_keys)
def test_scan_all_in_single_call(r: redis.Redis):
all_keys = key_val_dict(size=100)
assert all(r.set(k, v) for k, v in all_keys.items())
# Specify way more than the 100 keys we've added.
actual = r.scan(count=1000)
assert set(actual[1]) == set(all_keys)
assert actual[0] == 0
@pytest.mark.slow
def test_scan_expired_key(r: redis.Redis):
r.set("expiringkey", "value")
r.pexpire("expiringkey", 1)
sleep(1)
assert r.scan()[1] == []
def test_scan_stream(r: redis.Redis):
r.xadd("mystream", {"test": "value"})
assert r.type("mystream") == b"stream" # noqa: E721
for s in r.scan_iter(_type="STRING"):
print(s)