Merging upstream version 1.12.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
d6445459ac
commit
7865f9a813
20 changed files with 536 additions and 80 deletions
|
@ -61,6 +61,7 @@ def test_hello_command_is_not_supported(cli):
|
|||
cli.expect("IRedis currently not support RESP3")
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="unstable, maybe due to github action's signal handling")
|
||||
def test_abort_reading_connection(cli):
|
||||
cli.sendline("blpop mylist 30")
|
||||
cli.send(chr(3))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import re
|
||||
import tempfile
|
||||
from textwrap import dedent
|
||||
|
||||
|
@ -17,6 +18,22 @@ TIMEOUT = 2
|
|||
HISTORY_FILE = ".iredis_history"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def token_should_match():
|
||||
def match_func(token, tomatch):
|
||||
assert re.fullmatch(token, tomatch) is not None
|
||||
|
||||
return match_func
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def token_should_not_match():
|
||||
def match_func(token, tomatch):
|
||||
assert re.fullmatch(token, tomatch) is None
|
||||
|
||||
return match_func
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def judge_command():
|
||||
def judge_command_func(input_text, expect):
|
||||
|
|
|
@ -54,3 +54,27 @@ def test_command_with_key_in_quotes(judge_command):
|
|||
judge_command(
|
||||
'cluster keyslot "mykey "', {"command": "cluster keyslot", "key": '"mykey "'}
|
||||
)
|
||||
|
||||
|
||||
def test_timeout(token_should_match, token_should_not_match):
|
||||
from iredis.redis_grammar import TIMEOUT
|
||||
|
||||
token_should_match(TIMEOUT, "1.1")
|
||||
token_should_match(TIMEOUT, "1.0")
|
||||
token_should_match(TIMEOUT, ".1")
|
||||
token_should_match(TIMEOUT, "123123.1123")
|
||||
token_should_not_match(TIMEOUT, "1.")
|
||||
token_should_not_match(TIMEOUT, ".")
|
||||
token_should_not_match(TIMEOUT, ".a")
|
||||
|
||||
|
||||
def test_lr_const(token_should_match, token_should_not_match):
|
||||
from iredis.redis_grammar import LR_CONST
|
||||
|
||||
token_should_match(LR_CONST, "left")
|
||||
token_should_match(LR_CONST, "right")
|
||||
token_should_match(LR_CONST, "LEFT")
|
||||
token_should_match(LR_CONST, "RIGHT")
|
||||
token_should_not_match(LR_CONST, "righ")
|
||||
token_should_not_match(LR_CONST, "ab")
|
||||
token_should_not_match(LR_CONST, "123")
|
||||
|
|
|
@ -71,7 +71,7 @@ def test_client_tracking(judge_command):
|
|||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefix": "foo",
|
||||
"prefixes": "foo",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
|
@ -80,7 +80,7 @@ def test_client_tracking(judge_command):
|
|||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefix": "foo",
|
||||
"prefixes": "foo",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
|
@ -89,9 +89,28 @@ def test_client_tracking(judge_command):
|
|||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefix": "foo",
|
||||
"prefixes": "foo",
|
||||
"bcast_const": "BCAST",
|
||||
"noloop_const": "NOLOOP",
|
||||
"optin_const": "OPTIN",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT TRACKING ON PREFIX foo bar ok BCAST NOLOOP OPTIN",
|
||||
{
|
||||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefixes": "foo bar ok",
|
||||
"bcast_const": "BCAST",
|
||||
"noloop_const": "NOLOOP",
|
||||
"optin_const": "OPTIN",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_client_pause(judge_command):
|
||||
judge_command(
|
||||
"CLIENT PAUSE 20 WRITE",
|
||||
{"command": "CLIENT PAUSE", "timeout": "20", "pause_type": "WRITE"},
|
||||
)
|
||||
|
|
|
@ -177,3 +177,42 @@ def test_restore(judge_command):
|
|||
"value": '"\n\x17\x17\x00\x00\x00\x12\x00\x00\x00\x03\x00\x00\xc0\x01\x00\x04\xc0\x02\x00\x04\xc0\x03\x00\xff\x04\x00u#<\xc0;.\xe9\xdd"', # noqa
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_copy(judge_command):
|
||||
judge_command(
|
||||
"COPY foo bar DB 3 REPLACE",
|
||||
{
|
||||
"command": "COPY",
|
||||
"key": ["foo", "bar"],
|
||||
"db_const": "DB",
|
||||
"index": "3",
|
||||
"replace_const": "REPLACE",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"COPY foo bar REPLACE",
|
||||
{"command": "COPY", "key": ["foo", "bar"], "replace_const": "REPLACE"},
|
||||
)
|
||||
judge_command("COPY foo bar", {"command": "COPY", "key": ["foo", "bar"]})
|
||||
|
||||
|
||||
def test_getex(judge_command):
|
||||
judge_command("GETEX foo", {"command": "GETEX", "key": "foo"})
|
||||
judge_command(
|
||||
"GETEX bar ex 5",
|
||||
{"command": "GETEX", "key": "bar", "expiration": "ex", "millisecond": "5"},
|
||||
)
|
||||
judge_command(
|
||||
"GETEX bar px 5",
|
||||
{"command": "GETEX", "key": "bar", "expiration": "px", "millisecond": "5"},
|
||||
)
|
||||
judge_command(
|
||||
"GETEX bar pxat 5",
|
||||
{"command": "GETEX", "key": "bar", "pxat_const": "pxat", "timestampms": "5"},
|
||||
)
|
||||
judge_command(
|
||||
"GETEX bar exat 5",
|
||||
{"command": "GETEX", "key": "bar", "exat_const": "exat", "timestamp": "5"},
|
||||
)
|
||||
judge_command("GETEX bar ex 5 exat 5", None)
|
||||
|
|
|
@ -9,31 +9,37 @@ def test_geoadd(judge_command):
|
|||
"member": '"Catania"',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_georadiusbymember(judge_command):
|
||||
judge_command(
|
||||
"GEORADIUSBYMEMBER Sicily Agrigento 100 km",
|
||||
'GEOADD Sicily NX CH 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"',
|
||||
{
|
||||
"command": "GEORADIUSBYMEMBER",
|
||||
"command": "GEOADD",
|
||||
"condition": "NX",
|
||||
"changed": "CH",
|
||||
"key": "Sicily",
|
||||
"member": "Agrigento",
|
||||
"float": "100",
|
||||
"distunit": "km",
|
||||
"longitude": "15.087269",
|
||||
"latitude": "37.502669",
|
||||
"member": '"Catania"',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_georadius(judge_command):
|
||||
def test_geosearch(judge_command):
|
||||
judge_command(
|
||||
"GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD ",
|
||||
"GEOSEARCH Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST",
|
||||
{
|
||||
"command": "GEORADIUS",
|
||||
"command": "GEOSEARCH",
|
||||
"key": "Sicily",
|
||||
"longitude": "15",
|
||||
"latitude": "37",
|
||||
"float": "200",
|
||||
"distunit": "km",
|
||||
"geochoice": "WITHCOORD",
|
||||
"any": "FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_geosearchstore(judge_command):
|
||||
judge_command(
|
||||
"GEOSEARCHSTORE key2 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 STOREDIST",
|
||||
{
|
||||
"command": "GEOSEARCHSTORE",
|
||||
"key": ["Sicily", "key2"],
|
||||
"any": "FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 STOREDIST",
|
||||
},
|
||||
)
|
||||
|
|
|
@ -41,6 +41,18 @@ def test_brpoplpush(judge_command):
|
|||
judge_command("BRPOPLPUSH list1 list2 -1", None)
|
||||
|
||||
|
||||
def test_brpoplpush_with_double_timeout(judge_command):
|
||||
judge_command(
|
||||
"BRPOPLPUSH list1 list2 10.0",
|
||||
{"command": "BRPOPLPUSH", "key": "list1", "newkey": "list2", "timeout": "10.0"},
|
||||
)
|
||||
judge_command(
|
||||
"BRPOPLPUSH list1 list2 .2",
|
||||
{"command": "BRPOPLPUSH", "key": "list1", "newkey": "list2", "timeout": ".2"},
|
||||
)
|
||||
judge_command("BRPOPLPUSH list1 list2 12.", None)
|
||||
|
||||
|
||||
def test_linsert(judge_command):
|
||||
judge_command(
|
||||
'LINSERT mylist BEFORE "World" "There"',
|
||||
|
@ -106,3 +118,26 @@ def test_lpos(judge_command):
|
|||
"rank": "-1",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_blmove(judge_command):
|
||||
judge_command(
|
||||
"blmove list1 list2 left right 1.2",
|
||||
{
|
||||
"command": "blmove",
|
||||
"key": ["list1", "list2"],
|
||||
"lr_const": ["left", "right"],
|
||||
"timeout": "1.2",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"blmove list1 list2 right right .2",
|
||||
{
|
||||
"command": "blmove",
|
||||
"key": ["list1", "list2"],
|
||||
"lr_const": ["right", "right"],
|
||||
"timeout": ".2",
|
||||
},
|
||||
)
|
||||
judge_command("blmove list1 list2 right right", None)
|
||||
judge_command("blmove list1 right right 1", None)
|
||||
|
|
|
@ -31,6 +31,20 @@ def test_client_list(judge_command):
|
|||
{"command": "client list", "type_const": "TYPE", "conntype": "REPLICA"},
|
||||
)
|
||||
|
||||
judge_command(
|
||||
"client list TYPE REPLICA id 1 2 3",
|
||||
{
|
||||
"command": "client list",
|
||||
"type_const": "TYPE",
|
||||
"conntype": "REPLICA",
|
||||
"clientids": "1 2 3",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"client list ID 1 2 3",
|
||||
{"command": "client list", "clientids": "1 2 3"},
|
||||
)
|
||||
|
||||
|
||||
def test_configset(judge_command):
|
||||
judge_command(
|
||||
|
@ -71,6 +85,18 @@ def test_client_kill(judge_command):
|
|||
"CLIENT KILL 127.0.0.1:12345 ",
|
||||
{"command": "CLIENT KILL", "ip_port": "127.0.0.1:12345"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL ADDR 127.0.0.1:12345 ",
|
||||
{"command": "CLIENT KILL", "ip_port": "127.0.0.1:12345", "addr": "ADDR"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL LADDR 127.0.0.1:12345 ",
|
||||
{"command": "CLIENT KILL", "ip_port": "127.0.0.1:12345", "laddr": "LADDR"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL USER myuser",
|
||||
{"command": "CLIENT KILL", "const_user": "USER", "username": "myuser"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL id 123455 type pubsub skipme no",
|
||||
{
|
||||
|
@ -199,3 +225,48 @@ def test_acl_setuser(judge_command):
|
|||
def test_acl_getuser(judge_command):
|
||||
judge_command("acl getuser alan", {"command": "acl getuser", "username": "alan"})
|
||||
judge_command("acl getuser", None)
|
||||
|
||||
|
||||
def test_failover(judge_command):
|
||||
judge_command(
|
||||
"failover to 10.0.0.5 7379 abort timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"to_const": "to",
|
||||
"host": "10.0.0.5",
|
||||
"port": "7379",
|
||||
"abort_const": "abort",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"failover abort timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"abort_const": "abort",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"failover timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"failover to 10.0.0.5 7379 force abort timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"to_const": "to",
|
||||
"force": "force",
|
||||
"host": "10.0.0.5",
|
||||
"port": "7379",
|
||||
"abort_const": "abort",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
|
|
|
@ -33,7 +33,7 @@ def test_send_command(_input, command_name, expect_args):
|
|||
client = Client("127.0.0.1", "6379", None)
|
||||
client.execute = MagicMock()
|
||||
next(client.send_command(_input, None))
|
||||
args, kwargs = client.execute.call_args
|
||||
args, _ = client.execute.call_args
|
||||
assert args == (command_name, *expect_args)
|
||||
|
||||
|
||||
|
@ -511,7 +511,7 @@ def test_reissue_command_on_redis_cluster_with_password_in_dsn(
|
|||
assert call_args[0].password == "bar"
|
||||
|
||||
|
||||
def test_version_parse(iredis_client):
|
||||
def test_version_parse_for_auth(iredis_client):
|
||||
"""
|
||||
fix: https://github.com/laixintao/iredis/issues/418
|
||||
"""
|
||||
|
@ -521,3 +521,46 @@ def test_version_parse(iredis_client):
|
|||
assert command2syntax["AUTH"] == "command_password"
|
||||
iredis_client.auth_compat("5.0.14.1")
|
||||
assert command2syntax["AUTH"] == "command_password"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"info, version",
|
||||
[
|
||||
(
|
||||
(
|
||||
"# Server\r\nredis_version:df--128-NOTFOUND\r\n"
|
||||
"redis_mode:standalone\r\narch_bits:64"
|
||||
),
|
||||
"df--128-NOTFOUND",
|
||||
),
|
||||
(
|
||||
(
|
||||
"# Server\r\nredis_version:6.2.5\r\n"
|
||||
"redis_git_sha1:00000000\r\n"
|
||||
"redis_git_dirty:0\r\n"
|
||||
"redis_build_id:915e5480613bc9b6\r\n"
|
||||
"redis_mode:standalone "
|
||||
),
|
||||
"6.2.5",
|
||||
),
|
||||
(
|
||||
(
|
||||
"# Server\r\nredis_version:5.0.14.1\r\n"
|
||||
"redis_git_sha1:00000000\r\nredis_git_dirty:0\r\n"
|
||||
"redis_build_id:915e5480613bc9b6\r\n"
|
||||
"redis_mode:standalone "
|
||||
),
|
||||
"5.0.14.1",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_version_path(info, version):
|
||||
with patch("iredis.client.config") as mock_config:
|
||||
mock_config.no_info = True
|
||||
mock_config.pager = "less"
|
||||
mock_config.version = "5.0.0"
|
||||
with patch("iredis.client.Client.execute") as mock_execute:
|
||||
mock_execute.return_value = info
|
||||
client = Client("127.0.0.1", "6379", None)
|
||||
client.get_server_info()
|
||||
assert mock_config.version == version
|
||||
|
|
|
@ -183,7 +183,7 @@ def test_group_completer():
|
|||
@patch("iredis.completers.pendulum.now")
|
||||
def test_timestamp_completer_humanize_time_completion(fake_now):
|
||||
fake_now.return_value = pendulum.from_timestamp(1578487013)
|
||||
c = TimestampCompleter()
|
||||
c = TimestampCompleter(is_milliseconds=True, future_time=False)
|
||||
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "30"
|
||||
|
@ -260,8 +260,87 @@ def test_timestamp_completer_humanize_time_completion(fake_now):
|
|||
]
|
||||
|
||||
|
||||
@patch("iredis.completers.pendulum.now")
|
||||
def test_timestamp_completer_humanize_time_completion_seconds(fake_now):
|
||||
fake_now.return_value = pendulum.from_timestamp(1578487013)
|
||||
c = TimestampCompleter(is_milliseconds=False, future_time=False)
|
||||
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "30"
|
||||
completions = list(c.get_completions(fake_document, None))
|
||||
|
||||
assert completions == [
|
||||
Completion(
|
||||
text="1575895013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1575895013")]),
|
||||
display_meta="30 days ago (2019-12-09 12:36:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578379013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578379013")]),
|
||||
display_meta="30 hours ago (2020-01-07 06:36:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578485213",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578485213")]),
|
||||
display_meta="30 minutes ago (2020-01-08 12:06:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578486983",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578486983")]),
|
||||
display_meta="30 seconds ago (2020-01-08 12:36:23)",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@patch("iredis.completers.pendulum.now")
|
||||
def test_timestamp_completer_humanize_time_completion_seconds_future_time(fake_now):
|
||||
fake_now.return_value = pendulum.from_timestamp(1578487013)
|
||||
c = TimestampCompleter(is_milliseconds=False, future_time=True)
|
||||
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "30"
|
||||
completions = list(c.get_completions(fake_document, None))
|
||||
|
||||
print(completions)
|
||||
for c in completions:
|
||||
print(c.text)
|
||||
print(c.display)
|
||||
print(c.display_meta)
|
||||
assert completions == [
|
||||
Completion(
|
||||
text="1578487043",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578487043")]),
|
||||
display_meta="30 seconds later (2020-01-08 12:37:23)",
|
||||
),
|
||||
Completion(
|
||||
text="1578488813",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578488813")]),
|
||||
display_meta="30 minutes later (2020-01-08 13:06:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578595013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578595013")]),
|
||||
display_meta="30 hours later (2020-01-09 18:36:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1581079013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1581079013")]),
|
||||
display_meta="30 days later (2020-02-07 12:36:53)",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_timestamp_completer_datetime_format_time_completion():
|
||||
c = TimestampCompleter()
|
||||
c = TimestampCompleter(is_milliseconds=True, future_time=False)
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "2020-02-07"
|
||||
completions = list(c.get_completions(fake_document, None))
|
||||
|
@ -299,14 +378,18 @@ def test_completion_casing():
|
|||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == [
|
||||
"get",
|
||||
"getex",
|
||||
"getset",
|
||||
"getdel",
|
||||
"getbit",
|
||||
"geopos",
|
||||
"geoadd",
|
||||
"geohash",
|
||||
"geodist",
|
||||
"getrange",
|
||||
"geosearch",
|
||||
"georadius",
|
||||
"geosearchstore",
|
||||
"georadiusbymember",
|
||||
]
|
||||
|
||||
|
@ -314,19 +397,19 @@ def test_completion_casing():
|
|||
fake_document.text = fake_document.text_before_cursor = "GET"
|
||||
assert [
|
||||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == ["GET", "GETSET", "GETBIT", "GETRANGE"]
|
||||
] == ["GET", "GETEX", "GETSET", "GETDEL", "GETBIT", "GETRANGE"]
|
||||
|
||||
c = IRedisCompleter(completion_casing="upper")
|
||||
fake_document.text = fake_document.text_before_cursor = "get"
|
||||
assert [
|
||||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == ["GET", "GETSET", "GETBIT", "GETRANGE"]
|
||||
] == ["GET", "GETEX", "GETSET", "GETDEL", "GETBIT", "GETRANGE"]
|
||||
|
||||
c = IRedisCompleter(completion_casing="lower")
|
||||
fake_document.text = fake_document.text_before_cursor = "GET"
|
||||
assert [
|
||||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == ["get", "getset", "getbit", "getrange"]
|
||||
] == ["get", "getex", "getset", "getdel", "getbit", "getrange"]
|
||||
|
||||
|
||||
def test_username_completer():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue