Skip to content

Commit

Permalink
Fix scan
Browse files Browse the repository at this point in the history
  • Loading branch information
cunla committed May 10, 2023
1 parent 005388b commit da26cd9
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 92 deletions.
4 changes: 2 additions & 2 deletions fakeredis/_basefakesocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def _scan(self, keys, cursor, *args):
cursor = bin_reverse(cursor, bits_len)
if cursor >= len(keys):
return [0, []]
result_cursor = bin_reverse(cursor + count, bits_len)
result_cursor = cursor + count
result_data = []

regex = compile_pattern(pattern) if pattern is not None else None
Expand All @@ -325,7 +325,7 @@ def match_type(key):

if result_cursor >= len(data):
result_cursor = 0
return [str(result_cursor).encode(), result_data]
return [str(bin_reverse(result_cursor, bits_len)).encode(), result_data]

def _ttl(self, key, scale):
if not key:
Expand Down
88 changes: 0 additions & 88 deletions test/test_mixins/test_generic_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,40 +59,6 @@ def test_ttl_should_return_minus_one_for_non_expiring_key(r):
assert r.ttl('foo') == -1


def test_scan(r):
# 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(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(results) == 2


def test_sort_range_offset_range(r):
r.rpush('foo', '2')
r.rpush('foo', '1')
Expand Down Expand Up @@ -661,60 +627,6 @@ def test_delete_multiple(r):
def test_delete_nonexistent_key(r):
assert r.delete('foo') == 0


def test_scan_single(r):
r.set('foo1', 'bar1')
assert r.scan(match="foo*") == (0, [b'foo1'])


def test_scan_iter_single_page(r):
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):
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):
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):
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):
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):
r.set('expiringkey', 'value')
r.pexpire('expiringkey', 1)
sleep(1)
assert r.scan()[1] == []


def test_basic_sort(r):
r.rpush('foo', '2')
r.rpush('foo', '1')
Expand Down
92 changes: 90 additions & 2 deletions test/test_scan.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from time import sleep

import pytest
import redis

Expand Down Expand Up @@ -100,6 +102,92 @@ def test_scan_add_key_while_scanning_should_return_all_keys(r: redis.Redis):
cursor, data = r.scan(cursor=cursor)
keys.extend(data)

# assert len(set(keys)) == len(keys)
keys = set(keys)
assert len(keys) == size+1, f"{set(all_keys_dict).difference(keys)} is not empty but should be"
assert len(keys) >= size, f"{set(all_keys_dict).difference(keys)} is not empty but should be"


def test_scan(r):
# 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):
r.set('foo1', 'bar1')
assert r.scan(match="foo*") == (0, [b'foo1'])


def test_scan_iter_single_page(r):
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):
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):
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):
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):
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):
r.set('expiringkey', 'value')
r.pexpire('expiringkey', 1)
sleep(1)
assert r.scan()[1] == []

0 comments on commit da26cd9

Please sign in to comment.