diff options
Diffstat (limited to 'tests/unittests/command_parse')
-rw-r--r-- | tests/unittests/command_parse/test_base_token.py | 80 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_cluster.py | 255 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_connection.py | 116 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_generic_parse.py | 218 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_geo.py | 45 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_hash_parse.py | 66 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_hll_parse.py | 5 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_list_parse.py | 143 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_pubsub.py | 15 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_script.py | 22 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_server.py | 272 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_set_parse.py | 40 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_sorted_set_parse.py | 172 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_stream.py | 459 | ||||
-rw-r--r-- | tests/unittests/command_parse/test_string_parse.py | 345 |
15 files changed, 2253 insertions, 0 deletions
diff --git a/tests/unittests/command_parse/test_base_token.py b/tests/unittests/command_parse/test_base_token.py new file mode 100644 index 0000000..545bc92 --- /dev/null +++ b/tests/unittests/command_parse/test_base_token.py @@ -0,0 +1,80 @@ +def test_ip_match(judge_command): + def ip_valid(ip, valid): + if valid: + judge_command( + f"cluster meet {ip} 6379", + {"command": "cluster meet", "ip": ip, "port": "6379"}, + ) + else: + judge_command(f"cluster meet {ip} 6379", None) + + ip_valid("192.168.0.1", True) + ip_valid("255.255.255.255", True) + ip_valid("192.168.0.256", False) + ip_valid("192.256.0.26", False) + ip_valid("192.255.256.26", False) + ip_valid("0.0.0.0", True) + ip_valid("99.999.100.1", False) + ip_valid("300.168.0.1", False) + + +def test_port_match(judge_command): + def port_valid(port, valid): + if valid: + judge_command( + f"cluster meet 192.168.0.1 {port}", + {"command": "cluster meet", "ip": "192.168.0.1", "port": port}, + ) + else: + judge_command(f"cluster meet 192.168.0.1 {port}", None) + + port_valid("65535", True) + port_valid("0", False) + port_valid("1", True) + port_valid("192.168.0.256", False) + port_valid("65536", False) + port_valid("65545", False) + port_valid("65635", False) + port_valid("66535", False) + port_valid("75535", False) + port_valid("1024", True) + port_valid("6553", True) + port_valid("99999", False) + port_valid("99999999", False) + + +def test_command_with_key_in_quotes(judge_command): + judge_command( + 'cluster keyslot "mykey"', {"command": "cluster keyslot", "key": '"mykey"'} + ) + judge_command( + 'cluster keyslot "\\"mykey"', + {"command": "cluster keyslot", "key": '"\\"mykey"'}, + ) + 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") diff --git a/tests/unittests/command_parse/test_cluster.py b/tests/unittests/command_parse/test_cluster.py new file mode 100644 index 0000000..6dd877f --- /dev/null +++ b/tests/unittests/command_parse/test_cluster.py @@ -0,0 +1,255 @@ +""" +redis command in `cluster` group parse test. +""" + + +def test_command_cluster_addslots(judge_command): + judge_command("cluster addslots 1", {"command": "cluster addslots", "slots": "1"}) + judge_command("CLUSTER ADDSLOTS 1", {"command": "CLUSTER ADDSLOTS", "slots": "1"}) + judge_command( + "cluster addslots 1 2 3 4", {"command": "cluster addslots", "slots": "1 2 3 4"} + ) + judge_command("cluster addslots 1 a", None) + judge_command("cluster addslots a", None) + judge_command("cluster addslots a 4", None) + judge_command("cluster addslots abc", None) + + +def test_command_cluster_count_failure_reports(judge_command): + judge_command( + "cluster count-failure-reports 1", + {"command": "cluster count-failure-reports", "node": "1"}, + ) + judge_command( + "CLUSTER COUNT-FAILURE-REPORTS 1", + {"command": "CLUSTER COUNT-FAILURE-REPORTS", "node": "1"}, + ) + judge_command("cluster count-failure-reports 1 2 3 4", None) + judge_command("cluster count-failure-reports 1 a", None) + judge_command( + "cluster count-failure-reports a", + {"command": "cluster count-failure-reports", "node": "a"}, + ) + judge_command("cluster count-failure-reports a 2", None) + judge_command( + "cluster count-failure-reports abc", + {"command": "cluster count-failure-reports", "node": "abc"}, + ) + + +def test_command_cluster_countkeysinslot(judge_command): + judge_command( + "cluster countkeysinslot 1", {"command": "cluster countkeysinslot", "slot": "1"} + ) + judge_command( + "CLUSTER COUNTKEYSINSLOT 1", {"command": "CLUSTER COUNTKEYSINSLOT", "slot": "1"} + ) + judge_command("cluster countkeysinslot 1 2 3 4", None) + judge_command("cluster countkeysinslot 1 a", None) + judge_command("cluster countkeysinslot a", None) + judge_command("cluster countkeysinslot a 4", None) + judge_command("cluster countkeysinslot abc", None) + + +def test_command_cluster_delslots(judge_command): + judge_command("cluster delslots 1", {"command": "cluster delslots", "slots": "1"}) + judge_command("CLUSTER DELSLOTS 1", {"command": "CLUSTER DELSLOTS", "slots": "1"}) + judge_command( + "cluster delslots 1 2 3 4", {"command": "cluster delslots", "slots": "1 2 3 4"} + ) + judge_command("cluster delslots 1 a", None) + judge_command("cluster delslots a", None) + judge_command("cluster delslots a 4", None) + judge_command("cluster delslots abc", None) + + +def test_command_cluster_failover(judge_command): + judge_command( + "cluster failover force", + {"command": "cluster failover", "failoverchoice": "force"}, + ) + judge_command( + "cluster failover takeover", + {"command": "cluster failover", "failoverchoice": "takeover"}, + ) + judge_command( + "CLUSTER FAILOVER FORCE", + {"command": "CLUSTER FAILOVER", "failoverchoice": "FORCE"}, + ) + judge_command( + "CLUSTER FAILOVER takeover", + {"command": "CLUSTER FAILOVER", "failoverchoice": "takeover"}, + ) + judge_command( + "CLUSTER FAILOVER TAKEOVER", + {"command": "CLUSTER FAILOVER", "failoverchoice": "TAKEOVER"}, + ) + + +def test_command_cluster_forget(judge_command): + judge_command("cluster forget 1", {"command": "cluster forget", "node": "1"}) + judge_command( + "CLUSTER COUNT-FAILURE-REPORTS 1", + {"command": "CLUSTER COUNT-FAILURE-REPORTS", "node": "1"}, + ) + judge_command("cluster forget 1 2 3 4", None) + judge_command("cluster forget 1 a", None) + judge_command("cluster forget a", {"command": "cluster forget", "node": "a"}) + judge_command("cluster forget a 2", None) + judge_command( + "cluster forget abc", + { + "command": "cluster forget", + "node": "abc", + }, + ) + judge_command( + "cluster forget 07c37dfeb235213a872192d90877d0cd55635b91", + { + "command": "cluster forget", + "node": "07c37dfeb235213a872192d90877d0cd55635b91", + }, + ) + + +def test_command_cluster_getkeysinslot(judge_command): + judge_command( + "cluster getkeysinslot 1 1", + {"command": "cluster getkeysinslot", "slot": "1", "count": "1"}, + ) + judge_command( + "CLUSTER GETKEYSINSLOT 1 1", + {"command": "CLUSTER GETKEYSINSLOT", "slot": "1", "count": "1"}, + ) + judge_command( + "cluster getkeysinslot 1123 1121", + {"command": "cluster getkeysinslot", "slot": "1123", "count": "1121"}, + ) + judge_command("cluster getkeysinslot 1 2 3 4", None) + judge_command("cluster getkeysinslot 1 a", None) + judge_command("cluster getkeysinslot a", None) + judge_command("cluster getkeysinslot a 4", None) + judge_command("cluster getkeysinslot abc", None) + + +def test_command_cluster_info(judge_command): + judge_command("cluster info", {"command": "cluster info"}) + judge_command("CLUSTER INFO", {"command": "CLUSTER INFO"}) + judge_command("CLUSTER INFO 1", None) + judge_command("Acluster info", "invalid") + + +def test_command_cluster_keyslot(judge_command): + judge_command( + "cluster keyslot mykey", {"command": "cluster keyslot", "key": "mykey"} + ) + judge_command( + "cluster keyslot MYKEY", {"command": "cluster keyslot", "key": "MYKEY"} + ) + judge_command( + "CLUSTER KEYSLOT MYKEY", {"command": "CLUSTER KEYSLOT", "key": "MYKEY"} + ) + + +def test_command_cluster_meet(judge_command): + judge_command( + "cluster meet 192.168.0.1 12200", + {"command": "cluster meet", "ip": "192.168.0.1", "port": "12200"}, + ) + judge_command( + "CLUSTER MEET 192.168.0.1 12200", + {"command": "CLUSTER MEET", "ip": "192.168.0.1", "port": "12200"}, + ) + + +def test_command_cluster_nodes(judge_command): + judge_command("cluster nodes", {"command": "cluster nodes"}) + judge_command("CLUSTER NODES", {"command": "CLUSTER NODES"}) + + +def test_command_cluster_reset(judge_command): + judge_command( + "cluster reset hard", {"command": "cluster reset", "resetchoice": "hard"} + ) + judge_command( + "cluster reset soft", {"command": "cluster reset", "resetchoice": "soft"} + ) + judge_command( + "CLUSTER RESET HARD", {"command": "CLUSTER RESET", "resetchoice": "HARD"} + ) + judge_command( + "CLUSTER RESET soft", {"command": "CLUSTER RESET", "resetchoice": "soft"} + ) + judge_command( + "CLUSTER RESET SOFT", {"command": "CLUSTER RESET", "resetchoice": "SOFT"} + ) + judge_command("CLUSTER RESET SOFT1", None) + judge_command("CLUSTER RESET SAOFT", None) + + +def test_command_cluster_set_config_epoch(judge_command): + judge_command("cluster set-config-epoch 123123 ad", None) + judge_command( + "cluster set-config-epoch 0 ", + {"command": "cluster set-config-epoch", "epoch": "0"}, + ) + judge_command( + "cluster set-config-epoch 123123 ", + {"command": "cluster set-config-epoch", "epoch": "123123"}, + ) + + +def test_command_cluster_set_slot(judge_command): + judge_command( + "cluster setslot 123 importing 123123", + { + "command": "cluster setslot", + "slot": "123", + "slotsubcmd": "importing", + "node": "123123", + }, + ) + judge_command( + "cluster setslot 123 migrating 123123", + { + "command": "cluster setslot", + "slot": "123", + "slotsubcmd": "migrating", + "node": "123123", + }, + ) + judge_command( + "cluster setslot 123 node 123123", + { + "command": "cluster setslot", + "slot": "123", + "slotsubcmd": "node", + "node": "123123", + }, + ) + judge_command( + "cluster setslot 123 node e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca", + { + "command": "cluster setslot", + "slot": "123", + "slotsubcmd": "node", + "node": "e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca", + }, + ) + judge_command( + "cluster setslot 123 MIGRATING 123123", + { + "command": "cluster setslot", + "slot": "123", + "slotsubcmd": "MIGRATING", + "node": "123123", + }, + ) + judge_command( + "cluster setslot 123 stable", + {"command": "cluster setslot", "slot": "123", "slotsubcmd": "stable"}, + ) + judge_command( + "cluster setslot 123 STABLE", + {"command": "cluster setslot", "slot": "123", "slotsubcmd": "STABLE"}, + ) diff --git a/tests/unittests/command_parse/test_connection.py b/tests/unittests/command_parse/test_connection.py new file mode 100644 index 0000000..2a1de26 --- /dev/null +++ b/tests/unittests/command_parse/test_connection.py @@ -0,0 +1,116 @@ +def test_auth(judge_command): + judge_command("auth 123", {"command": "auth", "password": "123"}) + + +def test_auth_redis6(judge_command): + from iredis.commands import command2syntax + from iredis.redis_grammar import get_command_grammar + + get_command_grammar.cache_clear() + + old = command2syntax["AUTH"] + command2syntax["AUTH"] = "command_usernamex_password" + judge_command( + "auth default 123", + {"command": "auth", "password": "123", "username": "default"}, + ) + judge_command("AUTH 123", {"command": "AUTH", "password": "123"}) + command2syntax["AUTH"] = old + + +def test_echo(judge_command): + judge_command("echo hello", {"command": "echo", "message": "hello"}) + + +def test_ping(judge_command): + judge_command("ping hello", {"command": "ping", "message": "hello"}) + judge_command("ping", {"command": "ping", "message": None}) + judge_command("ping hello world", None) + + +def test_select(judge_command): + for index in range(16): + judge_command(f"select {index}", {"command": "select", "index": str(index)}) + for index in range(16, 100): + judge_command(f"select {index}", None) + judge_command("select acb", None) + + +def test_swapdb(judge_command): + for index1 in range(16): + for index2 in range(16): + judge_command( + f"swapdb {index1} {index2}", + {"command": "swapdb", "index": [str(index1), str(index2)]}, + ) + judge_command("swapdb abc 1", None) + judge_command("swapdb 1", None) + + +def test_client_caching(judge_command): + judge_command("CLIENT CACHING YES", {"command": "CLIENT CACHING", "yes": "YES"}) + judge_command("CLIENT CACHING NO", {"command": "CLIENT CACHING", "yes": "NO"}) + judge_command("CLIENT CACHING", None) + judge_command("CLIENT CACHING abc", None) + + +def test_client_tracking(judge_command): + judge_command("CLIENT TRACKING on", {"command": "CLIENT TRACKING", "on_off": "on"}) + judge_command( + "CLIENT TRACKING ON REDIRECT 123", + { + "command": "CLIENT TRACKING", + "on_off": "ON", + "redirect_const": "REDIRECT", + "clientid": "123", + }, + ) + judge_command( + "CLIENT TRACKING ON PREFIX foo", + { + "command": "CLIENT TRACKING", + "on_off": "ON", + "prefix_const": "PREFIX", + "prefixes": "foo", + }, + ) + judge_command( + "CLIENT TRACKING ON PREFIX foo", + { + "command": "CLIENT TRACKING", + "on_off": "ON", + "prefix_const": "PREFIX", + "prefixes": "foo", + }, + ) + judge_command( + "CLIENT TRACKING ON PREFIX foo BCAST NOLOOP OPTIN", + { + "command": "CLIENT TRACKING", + "on_off": "ON", + "prefix_const": "PREFIX", + "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"}, + ) diff --git a/tests/unittests/command_parse/test_generic_parse.py b/tests/unittests/command_parse/test_generic_parse.py new file mode 100644 index 0000000..6c4b0f3 --- /dev/null +++ b/tests/unittests/command_parse/test_generic_parse.py @@ -0,0 +1,218 @@ +def test_del(judge_command): + judge_command("DEL abc", {"command": "DEL", "keys": "abc"}) + judge_command("DEL bc1", {"command": "DEL", "keys": "bc1"}) + judge_command("DEL 1", {"command": "DEL", "keys": "1"}) + judge_command('DEL "hello world"', {"command": "DEL", "keys": '"hello world"'}) + judge_command( + r'DEL "hell\"o world"', {"command": "DEL", "keys": r'"hell\"o world"'} + ) + judge_command("DEL abc def", {"command": "DEL", "keys": "abc def"}) + judge_command("DEL 1 2", {"command": "DEL", "keys": "1 2"}) + judge_command("DEL 'he \"llo'", {"command": "DEL", "keys": "'he \"llo'"}) + judge_command( + """DEL 'he "llo' "abc" 'def' """, + {"command": "DEL", "keys": "'he \"llo' \"abc\" 'def'"}, + ) + + +def test_exists(judge_command): + judge_command("EXISTS foo bar", {"command": "EXISTS", "keys": "foo bar"}) + judge_command("EXISTS foo", {"command": "EXISTS", "keys": "foo"}) + judge_command("EXISTS 1", {"command": "EXISTS", "keys": "1"}) + judge_command('EXISTS "foo bar"', {"command": "EXISTS", "keys": '"foo bar"'}) + judge_command(r'EXISTS "\""', {"command": "EXISTS", "keys": r'"\""'}) + + +def test_expire(judge_command): + judge_command("EXPIRE key 12", {"command": "EXPIRE", "key": "key", "second": "12"}) + judge_command("EXPIRE key a12", None) + judge_command("EXPIRE 12 12", {"command": "EXPIRE", "key": "12", "second": "12"}) + judge_command("EXPIRE 12", None) + + +def test_expireat(judge_command): + judge_command( + "EXPIRE key 1565787643", + {"command": "EXPIRE", "key": "key", "second": "1565787643"}, + ) + judge_command("EXPIRE key a12", None) + + +def test_keys(judge_command): + judge_command("KEYS *", {"command": "KEYS", "pattern": "*"}) + judge_command("KEYS *abc", {"command": "KEYS", "pattern": "*abc"}) + judge_command("keys abc*", {"command": "keys", "pattern": "abc*"}) + + +def test_move(judge_command): + judge_command("MOVE key 14", {"command": "MOVE", "key": "key", "index": "14"}) + + +def test_pexpire(judge_command): + judge_command( + "PEXPIRE key 12", {"command": "PEXPIRE", "key": "key", "millisecond": "12"} + ) + judge_command("PEXPIRE key a12", None) + judge_command( + "PEXPIRE 12 12", {"command": "PEXPIRE", "key": "12", "millisecond": "12"} + ) + judge_command("PEXPIRE 12", None) + + +def test_pexpireat(judge_command): + judge_command( + "PEXPIREAT key 1565787643", + {"command": "PEXPIREAT", "key": "key", "timestampms": "1565787643"}, + ) + judge_command("PEXPIREAT key a12", None) + + +def test_rename(judge_command): + judge_command( + "rename key newkey", {"command": "rename", "key": "key", "newkey": "newkey"} + ) + judge_command( + "rename 123 newkey", {"command": "rename", "key": "123", "newkey": "newkey"} + ) + judge_command("rename 123 ", None) + + +def test_scan(judge_command): + judge_command( + "SCAN 0 MATCH task* COUNT 15 TYPE string", + { + "command": "SCAN", + "cursor": "0", + "match": "MATCH", + "pattern": "task*", + "count_const": "COUNT", + "count": "15", + "type_const": "TYPE", + "type": "string", + }, + ) + judge_command("SCAN 0", {"command": "SCAN", "cursor": "0"}) + judge_command( + "SCAN 0 MATCH task*", + {"command": "SCAN", "cursor": "0", "match": "MATCH", "pattern": "task*"}, + ) + judge_command( + "SCAN 0 COUNT 15 TYPE string", + { + "command": "SCAN", + "cursor": "0", + "count_const": "COUNT", + "count": "15", + "type_const": "TYPE", + "type": "string", + }, + ) + + +def test_migrate(judge_command): + judge_command( + 'MIGRATE 192.168.1.34 6379 " " 0 5000 KEYS key1 key2 key3', + { + "command": "MIGRATE", + "host": "192.168.1.34", + "port": "6379", + "key": '" "', + "index": "0", + "timeout": "5000", + "const_keys": "KEYS", + "keys": "key1 key2 key3", + }, + ) + judge_command( + "MIGRATE 192.168.1.34 6379 foo 0 5000 auth password1 KEYS key1 key2 key3", + { + "command": "MIGRATE", + "host": "192.168.1.34", + "port": "6379", + "key": "foo", + "index": "0", + "timeout": "5000", + "const_keys": "KEYS", + "keys": "key1 key2 key3", + "auth": "auth", + "password": "password1", + }, + ) + judge_command( + "MIGRATE 192.168.1.34 6379 foo 0 5000 auth username1 password1 KEYS key1 key2 key3", + { + "command": "MIGRATE", + "host": "192.168.1.34", + "port": "6379", + "key": "foo", + "index": "0", + "timeout": "5000", + "const_keys": "KEYS", + "keys": "key1 key2 key3", + "auth": "auth", + "password": "password1", + "username": "username1", + }, + ) + + +def test_object(judge_command): + judge_command( + "object refcount mylist", + {"command": "object", "object": "refcount", "key": "mylist"}, + ) + + +def test_wait(judge_command): + judge_command("WAIT 3 100", {"command": "WAIT", "count": "3", "timeout": "100"}) + + +def test_restore(judge_command): + judge_command( + 'RESTORE mykey 0 "\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 + { + "command": "RESTORE", + "key": "mykey", + "timeout": "0", + "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) diff --git a/tests/unittests/command_parse/test_geo.py b/tests/unittests/command_parse/test_geo.py new file mode 100644 index 0000000..8502696 --- /dev/null +++ b/tests/unittests/command_parse/test_geo.py @@ -0,0 +1,45 @@ +def test_geoadd(judge_command): + judge_command( + 'GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"', + { + "command": "GEOADD", + "key": "Sicily", + "longitude": "15.087269", + "latitude": "37.502669", + "member": '"Catania"', + }, + ) + judge_command( + 'GEOADD Sicily NX CH 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"', + { + "command": "GEOADD", + "condition": "NX", + "changed": "CH", + "key": "Sicily", + "longitude": "15.087269", + "latitude": "37.502669", + "member": '"Catania"', + }, + ) + + +def test_geosearch(judge_command): + judge_command( + "GEOSEARCH Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST", + { + "command": "GEOSEARCH", + "key": "Sicily", + "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", + }, + ) diff --git a/tests/unittests/command_parse/test_hash_parse.py b/tests/unittests/command_parse/test_hash_parse.py new file mode 100644 index 0000000..2bde9e0 --- /dev/null +++ b/tests/unittests/command_parse/test_hash_parse.py @@ -0,0 +1,66 @@ +def test_hdel(judge_command): + judge_command("HDEL foo bar", {"command": "HDEL", "key": "foo", "fields": "bar"}) + judge_command( + "HDEL foo bar hello world", + {"command": "HDEL", "key": "foo", "fields": "bar hello world"}, + ) + + +def test_hmset(judge_command): + judge_command( + "HMSET foo bar hello-world", + {"command": "HMSET", "key": "foo", "field": "bar", "value": "hello-world"}, + ) + judge_command( + "HMSET foo bar hello-world key2 value2", + {"command": "HMSET", "key": "foo", "field": "key2", "value": "value2"}, + ) + + +def test_hexists(judge_command): + judge_command( + "HEXISTS foo bar", {"command": "HEXISTS", "key": "foo", "field": "bar"} + ) + judge_command("HEXISTS foo bar hello-world", None) + + +def test_hincrby(judge_command): + judge_command( + "HINCRBY foo bar 12", + {"command": "HINCRBY", "key": "foo", "field": "bar", "delta": "12"}, + ) + + +def test_hincrbyfloat(judge_command): + judge_command( + "HINCRBYFLOAT foo bar 12.1", + {"command": "HINCRBYFLOAT", "key": "foo", "field": "bar", "float": "12.1"}, + ) + + +def test_hset(judge_command): + judge_command( + "HSET foo bar hello", + {"command": "HSET", "key": "foo", "field": "bar", "value": "hello"}, + ) + + +def test_hrandfield(judge_command): + judge_command( + "HRANDFIELD coin", + {"command": "HRANDFIELD", "key": "coin"}, + ) + judge_command( + "HRANDFIELD coin -5 WITHVALUES", + { + "command": "HRANDFIELD", + "key": "coin", + "count": "-5", + "withvalues_const": "WITHVALUES", + }, + ) + judge_command( + "HRANDFIELD coin -5", + {"command": "HRANDFIELD", "key": "coin", "count": "-5"}, + ) + judge_command("HRANDFIELD coin WITHVALUES", None) diff --git a/tests/unittests/command_parse/test_hll_parse.py b/tests/unittests/command_parse/test_hll_parse.py new file mode 100644 index 0000000..b139eed --- /dev/null +++ b/tests/unittests/command_parse/test_hll_parse.py @@ -0,0 +1,5 @@ +def test_pfmerge(judge_command): + judge_command( + "PFMERGE hll3 hll1 hll2", + {"command": "PFMERGE", "newkey": "hll3", "keys": "hll1 hll2"}, + ) diff --git a/tests/unittests/command_parse/test_list_parse.py b/tests/unittests/command_parse/test_list_parse.py new file mode 100644 index 0000000..69a294e --- /dev/null +++ b/tests/unittests/command_parse/test_list_parse.py @@ -0,0 +1,143 @@ +def test_rpush(judge_command): + judge_command( + "RPUSH list1 foo bar hello world", + {"command": "RPUSH", "key": "list1", "values": "foo bar hello world"}, + ) + judge_command( + "LPUSH list1 foo", {"command": "LPUSH", "key": "list1", "values": "foo"} + ) + + +def test_lindex(judge_command): + judge_command( + "LINDEX list1 10", {"command": "LINDEX", "key": "list1", "position": "10"} + ) + judge_command( + "LINDEX list1 -10", {"command": "LINDEX", "key": "list1", "position": "-10"} + ) + judge_command("LINDEX list1 1.1", None) + + +def test_lset(judge_command): + judge_command( + "LSET list1 10 newbie", + {"command": "LSET", "key": "list1", "position": "10", "value": "newbie"}, + ) + judge_command( + "LSET list1 -1 newbie", + {"command": "LSET", "key": "list1", "position": "-1", "value": "newbie"}, + ) + + +def test_brpoplpush(judge_command): + judge_command( + "BRPOPLPUSH list1 list2 10", + {"command": "BRPOPLPUSH", "key": "list1", "newkey": "list2", "timeout": "10"}, + ) + judge_command( + "BRPOPLPUSH list1 list2 0", + {"command": "BRPOPLPUSH", "key": "list1", "newkey": "list2", "timeout": "0"}, + ) + 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"', + { + "command": "LINSERT", + "key": "mylist", + "position_choice": "BEFORE", + "value": ['"World"', '"There"'], + }, + ) + judge_command( + 'LINSERT mylist after "World" "There"', + { + "command": "LINSERT", + "key": "mylist", + "position_choice": "after", + "value": ['"World"', '"There"'], + }, + ) + + +def test_lpos(judge_command): + judge_command("LPOS mylist c", {"command": "LPOS", "key": "mylist", "element": "c"}) + judge_command( + "LPOS mylist c RANK 2", + { + "command": "LPOS", + "key": "mylist", + "element": "c", + "rank_const": "RANK", + "rank": "2", + }, + ) + judge_command( + "LPOS mylist c RANK -1", + { + "command": "LPOS", + "key": "mylist", + "element": "c", + "rank_const": "RANK", + "rank": "-1", + }, + ) + judge_command( + "LPOS mylist c COUNT 2", + { + "command": "LPOS", + "key": "mylist", + "element": "c", + "count_const": "COUNT", + "count": "2", + }, + ) + judge_command( + "LPOS mylist c RANK -1 COUNT 2", + { + "command": "LPOS", + "key": "mylist", + "element": "c", + "count_const": "COUNT", + "count": "2", + "rank_const": "RANK", + "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) diff --git a/tests/unittests/command_parse/test_pubsub.py b/tests/unittests/command_parse/test_pubsub.py new file mode 100644 index 0000000..c7a2b54 --- /dev/null +++ b/tests/unittests/command_parse/test_pubsub.py @@ -0,0 +1,15 @@ +def test_publish(judge_command): + judge_command( + "publish foo bar", {"command": "publish", "channel": "foo", "message": "bar"} + ) + + +def test_subscribe(judge_command): + judge_command("subscribe foo bar", {"command": "subscribe", "channel": "bar"}) + + +def test_pubsub(judge_command): + judge_command( + "PUBSUB NUMSUB foo bar", + {"command": "PUBSUB", "pubsubcmd": "NUMSUB", "channel": "bar"}, + ) diff --git a/tests/unittests/command_parse/test_script.py b/tests/unittests/command_parse/test_script.py new file mode 100644 index 0000000..3b984c3 --- /dev/null +++ b/tests/unittests/command_parse/test_script.py @@ -0,0 +1,22 @@ +def test_eval(judge_command): + judge_command( + 'eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second', + { + "command": "eval", + "double_lua": "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", + "any": "2 key1 key2 first second", + }, + ) + judge_command( + "eval 'return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}' 2 key1 key2 first second", + { + "command": "eval", + "single_lua": "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", + "any": "2 key1 key2 first second", + }, + ) + + +def test_scriptdebug(judge_command): + judge_command("SCRIPT DEBUG YES", {"command": "SCRIPT DEBUG", "scriptdebug": "YES"}) + judge_command("SCRIPT DEBUG no", {"command": "SCRIPT DEBUG", "scriptdebug": "no"}) diff --git a/tests/unittests/command_parse/test_server.py b/tests/unittests/command_parse/test_server.py new file mode 100644 index 0000000..5ecccbf --- /dev/null +++ b/tests/unittests/command_parse/test_server.py @@ -0,0 +1,272 @@ +def test_client_setname(judge_command): + judge_command( + "CLIENT SETNAME foobar", {"command": "CLIENT SETNAME", "value": "foobar"} + ) + + +def test_client_unblock(judge_command): + judge_command( + "CLIENT UNBLOCK 33 TIMEOUT", + {"command": "CLIENT UNBLOCK", "clientid": "33", "error": "TIMEOUT"}, + ) + judge_command("CLIENT UNBLOCK 33", {"command": "CLIENT UNBLOCK", "clientid": "33"}) + + +def test_flushdb(judge_command): + judge_command("FLUSHDB async", {"command": "FLUSHDB", "async": "async"}) + judge_command("FLUSHDB", {"command": "FLUSHDB"}) + judge_command("FLUSHDB ASYNC", {"command": "FLUSHDB", "async": "ASYNC"}) + judge_command("FLUSHALL ASYNC", {"command": "FLUSHALL", "async": "ASYNC"}) + + +def test_client_list(judge_command): + judge_command("client list", {"command": "client list"}) + judge_command("client list TYPE REPLICA1", None) + judge_command( + "client list type master", + {"command": "client list", "type_const": "type", "conntype": "master"}, + ) + judge_command( + "client list TYPE REPLICA", + {"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( + "config set foo bar", + {"command": "config set", "parameter": "foo", "value": "bar"}, + ) + judge_command( + "config set requirepass ''", + {"command": "config set", "parameter": "requirepass", "value": "''"}, + ) + + +def test_shutdown(judge_command): + judge_command("shutdown save", {"command": "shutdown", "shutdown": "save"}) + judge_command("shutdown NOSAVE", {"command": "shutdown", "shutdown": "NOSAVE"}) + + +def test_clientpause(judge_command): + judge_command("client pause 3000", {"command": "client pause", "timeout": "3000"}) + + +def test_client_reply(judge_command): + judge_command("client reply on", {"command": "client reply", "switch": "on"}) + + +def test_client_kill(judge_command): + judge_command( + "CLIENT KILL addr 127.0.0.1:12345 type pubsub", + { + "command": "CLIENT KILL", + "addr": "addr", + "ip_port": "127.0.0.1:12345", + "type_const": "type", + "conntype": "pubsub", + }, + ) + 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", + { + "command": "CLIENT KILL", + "const_id": "id", + "clientid": "123455", + "type_const": "type", + "conntype": "pubsub", + "skipme": "skipme", + "yes": "no", + }, + ) + + +def test_client_kill_username(judge_command): + """since redis-server 6.0""" + judge_command( + "client kill USER default", + {"command": "client kill", "const_user": "USER", "username": "default"}, + ) + + +def test_client_kill_unordered_arguments(judge_command): + judge_command( + "CLIENT KILL type pubsub addr 127.0.0.1:12345", + { + "command": "CLIENT KILL", + "addr": "addr", + "ip_port": "127.0.0.1:12345", + "type_const": "type", + "conntype": "pubsub", + }, + ) + + +def test_psync(judge_command): + judge_command( + "PSYNC abc 123", {"command": "PSYNC", "replicationid": "abc", "offset": "123"} + ) + judge_command("PSYNC", None) + + +def test_latency_graph(judge_command): + judge_command( + "latency graph command", {"command": "latency graph", "graphevent": "command"} + ) + judge_command( + "latency graph fork", {"command": "latency graph", "graphevent": "fork"} + ) + judge_command("latency graph", None) + + +def test_latency_reset(judge_command): + judge_command( + "latency reset command fork aof-fsync-always", + {"command": "latency reset", "graphevent": "aof-fsync-always"}, + ) + judge_command( + "latency reset fork", {"command": "latency reset", "graphevent": "fork"} + ) + judge_command("latency reset", {"command": "latency reset"}) + + +def test_lolwut(judge_command): + judge_command("lolwut", {"command": "lolwut"}) + # only works before redis 6 + judge_command("lolwut 5", {"command": "lolwut", "any": "5"}) + judge_command("lolwut 5 1", {"command": "lolwut", "any": "5 1"}) + # redis 6 + judge_command( + "lolwut VERSION 5 5", + {"command": "lolwut", "version": "VERSION", "version_num": "5", "any": "5"}, + ) + + +def test_info(judge_command): + judge_command("info cpu", {"command": "info", "section": "cpu"}) + judge_command("info", {"command": "info"}) + judge_command("info all", {"command": "info", "section": "all"}) + judge_command("info CPU", {"command": "info", "section": "CPU"}) + + +def test_bgsave(judge_command): + judge_command("bgsave", {"command": "bgsave"}) + judge_command("bgsave schedule", {"command": "bgsave", "schedule": "schedule"}) + judge_command("BGSAVE SCHEDULE", {"command": "BGSAVE", "schedule": "SCHEDULE"}) + + +def test_acl_cat(judge_command): + judge_command("acl cat", {"command": "acl cat"}) + judge_command("acl CAT", {"command": "acl CAT"}) + judge_command( + "ACL CAT scripting", {"command": "ACL CAT", "categoryname": "scripting"} + ) + judge_command("ACL CAT WATCH", {"command": "ACL CAT", "categoryname": "WATCH"}) + + +def test_acl_deluser(judge_command): + judge_command( + "acl deluser laixintao", {"command": "acl deluser", "username": "laixintao"} + ) + judge_command( + "acl deluser laixintao antirez", + {"command": "acl deluser", "username": "antirez"}, + ) + + +def test_acl_log(judge_command): + judge_command("acl log 2", {"command": "acl log", "count": "2"}) + judge_command("acl log reset", {"command": "acl log", "reset_const": "reset"}) + judge_command("acl log ", {"command": "acl log"}) + + +def test_acl_setuser(judge_command): + judge_command("ACL SETUSER alice", {"command": "ACL SETUSER", "username": "alice"}) + judge_command( + "ACL SETUSER alice on >p1pp0 ~cached:* +get", + {"command": "ACL SETUSER", "username": "alice", "rule": "+get"}, + ) + judge_command( + "ACL SETUSER alan allkeys +@string +@set -SADD >alanpassword", + {"command": "ACL SETUSER", "username": "alan", "rule": ">alanpassword"}, + ) + + +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", + }, + ) diff --git a/tests/unittests/command_parse/test_set_parse.py b/tests/unittests/command_parse/test_set_parse.py new file mode 100644 index 0000000..d35a52b --- /dev/null +++ b/tests/unittests/command_parse/test_set_parse.py @@ -0,0 +1,40 @@ +def test_sadd(judge_command): + judge_command( + "SADD foo m1 m2 m3", {"command": "SADD", "key": "foo", "members": "m1 m2 m3"} + ) + judge_command("SADD foo m1", {"command": "SADD", "key": "foo", "members": "m1"}) + judge_command("SADD foo", None) + + +def test_sdiffstore(judge_command): + judge_command( + "SDIFFSTORE foo m1 m2 m3", + {"command": "SDIFFSTORE", "destination": "foo", "keys": "m1 m2 m3"}, + ) + judge_command( + "SDIFFSTORE foo m1", + {"command": "SDIFFSTORE", "destination": "foo", "keys": "m1"}, + ) + judge_command("SDIFFSTORE foo", None) + + +def test_is_member(judge_command): + judge_command("SISMEMBER foo m1 m2 m3", None) + judge_command( + "SISMEMBER foo m1", {"command": "SISMEMBER", "key": "foo", "member": "m1"} + ) + judge_command("SISMEMBER foo", None) + + +def test_smove(judge_command): + judge_command( + "SMOVE foo bar m2", + {"command": "SMOVE", "key": "foo", "newkey": "bar", "member": "m2"}, + ) + judge_command("SMOVE foo m1", None) + judge_command("SMOVE foo", None) + + +def test_spop(judge_command): + judge_command("SPOP set", {"command": "SPOP", "key": "set"}) + judge_command("SPOP set 3", {"command": "SPOP", "key": "set", "count": "3"}) diff --git a/tests/unittests/command_parse/test_sorted_set_parse.py b/tests/unittests/command_parse/test_sorted_set_parse.py new file mode 100644 index 0000000..a0af616 --- /dev/null +++ b/tests/unittests/command_parse/test_sorted_set_parse.py @@ -0,0 +1,172 @@ +import pytest + + +def test_zcount(judge_command): + judge_command( + "zcount foo -10 0", + {"command": "zcount", "key": "foo", "min": "-10", "max": "0"}, + ) + + +def test_bzpopmax(judge_command): + judge_command( + "bzpopmax set set2 set3 4", + {"command": "bzpopmax", "keys": "set set2 set3", "timeout": "4"}, + ) + judge_command( + "bzpopmin set 4", {"command": "bzpopmin", "keys": "set", "timeout": "4"} + ) + + +def test_zadd(judge_command): + judge_command( + "zadd t 100 qewqr 23 pp 11 oo", + { + "command": "zadd", + "key": "t", + "score": "11", # FIXME: only have last one + "member": "oo", + }, + ) + judge_command( + "zadd t incr 100 foo", + { + "command": "zadd", + "key": "t", + "incr": "incr", + "score": "100", # FIXME: only have last one + "member": "foo", + }, + ) + judge_command( + "zadd t NX CH incr 100 foo", + { + "command": "zadd", + "key": "t", + "condition": "NX", + "changed": "CH", + "incr": "incr", + "score": "100", # FIXME: only have last one + "member": "foo", + }, + ) + + +def test_zincrby(judge_command): + judge_command( + "zincrby t 10 foo", + {"command": "zincrby", "key": "t", "float": "10", "member": "foo"}, + ) + judge_command( + "zincrby t 2.3 foo", + {"command": "zincrby", "key": "t", "float": "2.3", "member": "foo"}, + ) + + +def test_zlexcount(judge_command): + judge_command( + "zlexcount a - +", + {"command": "zlexcount", "key": "a", "lexmin": "-", "lexmax": "+"}, + ) + judge_command( + "zlexcount a (aaaa [z", + {"command": "zlexcount", "key": "a", "lexmin": "(aaaa", "lexmax": "[z"}, + ) + judge_command( + "ZLEXCOUNT myset - [c", + {"command": "ZLEXCOUNT", "key": "myset", "lexmin": "-", "lexmax": "[c"}, + ) + judge_command( + "ZLEXCOUNT myset [aaa (g", + {"command": "ZLEXCOUNT", "key": "myset", "lexmin": "[aaa", "lexmax": "(g"}, + ) + + +def test_zrange(judge_command): + judge_command( + "zrange foo -1 10", + {"command": "zrange", "key": "foo", "start": "-1", "end": "10"}, + ) + judge_command( + "zrange foo 0 -1", + {"command": "zrange", "key": "foo", "start": "0", "end": "-1"}, + ) + judge_command( + "zrange foo 0 -1 withscores", + { + "command": "zrange", + "key": "foo", + "start": "0", + "end": "-1", + "withscores": "withscores", + }, + ) + + +@pytest.mark.xfail(reason="Not implemented yet") +def test_zinterstore(judge_command): + judge_command("ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3", {}) + judge_command("ZINTERSTORE out 2 zset1 zset2 WEIGHTS -1 -2", {}) + judge_command("ZINTERSTORE out 2 zset1 zset2 WEIGHTS 0.2 0.3", {}) + + +def test_zrangebylex(judge_command): + judge_command( + "ZRANGEBYLEX myzset [aaa (g", + {"command": "ZRANGEBYLEX", "key": "myzset", "lexmin": "[aaa", "lexmax": "(g"}, + ) + judge_command( + "ZRANGEBYLEX myzset - (c", + {"command": "ZRANGEBYLEX", "key": "myzset", "lexmin": "-", "lexmax": "(c"}, + ) + judge_command( + "ZRANGEBYLEX myzset - (c limit 10 100", + { + "command": "ZRANGEBYLEX", + "key": "myzset", + "lexmin": "-", + "lexmax": "(c", + "limit": "limit", + "offset": "10", + "count": "100", + }, + ) + judge_command( + "ZRANGEBYLEX myzset - (c limit 10 -1", + { + "command": "ZRANGEBYLEX", + "key": "myzset", + "lexmin": "-", + "lexmax": "(c", + "limit": "limit", + "offset": "10", + "count": "-1", + }, + ) + + +def test_zrangebyscore(judge_command): + judge_command( + "ZRANGEBYSCORE myzset -inf +inf", + {"command": "ZRANGEBYSCORE", "key": "myzset", "min": "-inf", "max": "+inf"}, + ) + judge_command( + "ZRANGEBYSCORE myzset 1 2", + {"command": "ZRANGEBYSCORE", "key": "myzset", "min": "1", "max": "2"}, + ) + judge_command( + "ZRANGEBYSCORE myzset (1 (2", + {"command": "ZRANGEBYSCORE", "key": "myzset", "min": "(1", "max": "(2"}, + ) + judge_command( + "ZRANGEBYSCORE myzset -inf +inf LIMIT 10 100", + { + "command": "ZRANGEBYSCORE", + "key": "myzset", + "min": "-inf", + "max": "+inf", + "limit": "LIMIT", + "offset": "10", + "count": "100", + }, + ) diff --git a/tests/unittests/command_parse/test_stream.py b/tests/unittests/command_parse/test_stream.py new file mode 100644 index 0000000..82f8670 --- /dev/null +++ b/tests/unittests/command_parse/test_stream.py @@ -0,0 +1,459 @@ +def test_xrange(judge_command): + judge_command( + "XRANGE somestream - +", + {"command": "XRANGE", "key": "somestream", "stream_id": ["-", "+"]}, + ) + judge_command( + "XRANGE somestream 1526985054069 1526985055069", + { + "command": "XRANGE", + "key": "somestream", + "stream_id": ["1526985054069", "1526985055069"], + }, + ) + judge_command( + "XRANGE somestream 1526985054069 1526985055069-10", + { + "command": "XRANGE", + "key": "somestream", + "stream_id": ["1526985054069", "1526985055069-10"], + }, + ) + judge_command( + "XRANGE somestream 1526985054069 1526985055069-10 count 10", + { + "command": "XRANGE", + "key": "somestream", + "stream_id": ["1526985054069", "1526985055069-10"], + "count_const": "count", + "count": "10", + }, + ) + + +def test_xgroup_create(judge_command): + judge_command( + "XGROUP CREATE mykey mygroup 123", + { + "command": "XGROUP", + "stream_create": "CREATE", + "key": "mykey", + "group": "mygroup", + "stream_id": "123", + }, + ) + judge_command( + "XGROUP CREATE mykey mygroup $", + { + "command": "XGROUP", + "stream_create": "CREATE", + "key": "mykey", + "group": "mygroup", + "stream_id": "$", + }, + ) + # short of a parameter + judge_command("XGROUP CREATE mykey mygroup", None) + judge_command("XGROUP CREATE mykey", None) + + +def test_xgroup_setid(judge_command): + judge_command( + "XGROUP SETID mykey mygroup 123", + { + "command": "XGROUP", + "stream_setid": "SETID", + "key": "mykey", + "group": "mygroup", + "stream_id": "123", + }, + ) + judge_command( + "XGROUP SETID mykey mygroup $", + { + "command": "XGROUP", + "stream_setid": "SETID", + "key": "mykey", + "group": "mygroup", + "stream_id": "$", + }, + ) + # two subcommand together shouldn't match + judge_command("XGROUP CREATE mykey mygroup 123 SETID mykey mygroup $", None) + + +def test_xgroup_destroy(judge_command): + judge_command( + "XGROUP destroy mykey mygroup", + { + "command": "XGROUP", + "stream_destroy": "destroy", + "key": "mykey", + "group": "mygroup", + }, + ) + judge_command("XGROUP destroy mykey", None) + judge_command("XGROUP DESTROY mykey mygroup $", None) + + +def test_xgroup_delconsumer(judge_command): + judge_command( + "XGROUP delconsumer mykey mygroup myconsumer", + { + "command": "XGROUP", + "stream_delconsumer": "delconsumer", + "key": "mykey", + "group": "mygroup", + "consumer": "myconsumer", + }, + ) + judge_command( + "XGROUP delconsumer mykey mygroup $", + { + "command": "XGROUP", + "stream_delconsumer": "delconsumer", + "key": "mykey", + "group": "mygroup", + "consumer": "$", + }, + ) + judge_command("XGROUP delconsumer mykey mygroup", None) + + +def test_xgroup_stream(judge_command): + judge_command( + "XACK mystream group1 123123", + { + "command": "XACK", + "key": "mystream", + "group": "group1", + "stream_id": "123123", + }, + ) + judge_command( + "XACK mystream group1 123123 111", + {"command": "XACK", "key": "mystream", "group": "group1", "stream_id": "111"}, + ) + + +def test_xinfo(judge_command): + judge_command( + "XINFO consumers mystream mygroup", + { + "command": "XINFO", + "stream_consumers": "consumers", + "key": "mystream", + "group": "mygroup", + }, + ) + judge_command( + "XINFO GROUPS mystream", + {"command": "XINFO", "stream_groups": "GROUPS", "key": "mystream"}, + ) + judge_command( + "XINFO STREAM mystream", + {"command": "XINFO", "stream": "STREAM", "key": "mystream"}, + ) + judge_command("XINFO HELP", {"command": "XINFO", "help": "HELP"}) + judge_command("XINFO consumers mystream mygroup GROUPS mystream", None) + judge_command("XINFO groups mystream mygroup", None) + + +def test_xinfo_with_full(judge_command): + judge_command( + "XINFO STREAM mystream FULL", + { + "command": "XINFO", + "stream": "STREAM", + "key": "mystream", + "full_const": "FULL", + }, + ) + judge_command( + "XINFO STREAM mystream FULL count 10", + { + "command": "XINFO", + "stream": "STREAM", + "key": "mystream", + "full_const": "FULL", + "count_const": "count", + "count": "10", + }, + ) + + +def test_xpending(judge_command): + judge_command( + "XPENDING mystream group55", + {"command": "XPENDING", "key": "mystream", "group": "group55"}, + ) + judge_command( + "XPENDING mystream group55 myconsumer", + { + "command": "XPENDING", + "key": "mystream", + "group": "group55", + "consumer": "myconsumer", + }, + ) + judge_command( + "XPENDING mystream group55 - + 10", + { + "command": "XPENDING", + "key": "mystream", + "group": "group55", + "stream_id": ["-", "+"], + "count": "10", + }, + ) + judge_command( + "XPENDING mystream group55 - + 10 myconsumer", + { + "command": "XPENDING", + "key": "mystream", + "group": "group55", + "stream_id": ["-", "+"], + "count": "10", + "consumer": "myconsumer", + }, + ) + judge_command("XPENDING mystream group55 - + ", None) + + +def test_xadd(judge_command): + judge_command( + "xadd mystream MAXLEN ~ 1000 * key value", + { + "command": "xadd", + "key": "mystream", + "maxlen": "MAXLEN", + "approximately": "~", + "count": "1000", + "sfield": "key", + "svalue": "value", + "stream_id": "*", + }, + ) + # test for MAXLEN option + judge_command( + "xadd mystream MAXLEN 1000 * key value", + { + "command": "xadd", + "key": "mystream", + "maxlen": "MAXLEN", + "count": "1000", + "sfield": "key", + "svalue": "value", + "stream_id": "*", + }, + ) + judge_command( + "xadd mystream * key value", + { + "command": "xadd", + "key": "mystream", + "sfield": "key", + "svalue": "value", + "stream_id": "*", + }, + ) + # spcify stream id + judge_command( + "xadd mystream 123-123 key value", + { + "command": "xadd", + "key": "mystream", + "sfield": "key", + "svalue": "value", + "stream_id": "123-123", + }, + ) + judge_command( + "xadd mystream 123-123 key value foo bar hello world", + { + "command": "xadd", + "key": "mystream", + "sfield": "hello", + "svalue": "world", + "stream_id": "123-123", + }, + ) + + +def test_xtrim(judge_command): + judge_command( + " XTRIM mystream MAXLEN 2", + {"command": "XTRIM", "key": "mystream", "maxlen": "MAXLEN", "count": "2"}, + ) + judge_command( + " XTRIM mystream MAXLEN ~ 2", + { + "command": "XTRIM", + "key": "mystream", + "maxlen": "MAXLEN", + "count": "2", + "approximately": "~", + }, + ) + judge_command(" XTRIM mystream", None) + + +def test_xdel(judge_command): + judge_command( + "XDEL mystream 1581165000000 1549611229000 1581060831000", + {"command": "XDEL", "key": "mystream", "stream_id": "1581060831000"}, + ) + judge_command( + "XDEL mystream 1581165000000", + {"command": "XDEL", "key": "mystream", "stream_id": "1581165000000"}, + ) + + +def test_xclaim(judge_command): + judge_command( + "XCLAIM mystream mygroup Alice 3600000 1526569498055-0", + { + "command": "XCLAIM", + "key": "mystream", + "group": "mygroup", + "consumer": "Alice", + "millisecond": "3600000", + "stream_id": "1526569498055-0", + }, + ) + judge_command( + "XCLAIM mystream mygroup Alice 3600000 1526569498055-0 123 456 789", + { + "command": "XCLAIM", + "key": "mystream", + "group": "mygroup", + "consumer": "Alice", + "millisecond": "3600000", + "stream_id": "789", + }, + ) + judge_command( + "XCLAIM mystream mygroup Alice 3600000 1526569498055-0 IDLE 300", + { + "command": "XCLAIM", + "key": "mystream", + "group": "mygroup", + "consumer": "Alice", + "millisecond": ["3600000", "300"], + "stream_id": "1526569498055-0", + "idle": "IDLE", + }, + ) + judge_command( + "XCLAIM mystream mygroup Alice 3600000 1526569498055-0 retrycount 7", + { + "command": "XCLAIM", + "key": "mystream", + "group": "mygroup", + "consumer": "Alice", + "millisecond": "3600000", + "stream_id": "1526569498055-0", + "retrycount": "retrycount", + "count": "7", + }, + ) + judge_command( + "XCLAIM mystream mygroup Alice 3600000 1526569498055-0 TIME 123456789", + { + "command": "XCLAIM", + "key": "mystream", + "group": "mygroup", + "consumer": "Alice", + "millisecond": "3600000", + "stream_id": "1526569498055-0", + "time": "TIME", + "timestamp": "123456789", + }, + ) + judge_command( + "XCLAIM mystream mygroup Alice 3600000 1526569498055-0 FORCE", + { + "command": "XCLAIM", + "key": "mystream", + "group": "mygroup", + "consumer": "Alice", + "millisecond": "3600000", + "stream_id": "1526569498055-0", + "force": "FORCE", + }, + ) + judge_command( + "XCLAIM mystream mygroup Alice 3600000 1526569498055-0 JUSTID", + { + "command": "XCLAIM", + "key": "mystream", + "group": "mygroup", + "consumer": "Alice", + "millisecond": "3600000", + "stream_id": "1526569498055-0", + "justid": "JUSTID", + }, + ) + + +def test_xread(judge_command): + judge_command( + "XREAD COUNT 2 STREAMS mystream writers 0-0 0-0", + { + "command": "XREAD", + "count_const": "COUNT", + "count": "2", + "streams": "STREAMS", + # FIXME current grammar can't support multiple tokens + # so the ids will be recognized to keys. + "keys": "mystream writers 0-0", + "stream_id": "0-0", + }, + ) + judge_command( + "XREAD COUNT 2 BLOCK 1000 STREAMS mystream writers 0-0 0-0", + { + "command": "XREAD", + "count_const": "COUNT", + "count": "2", + "streams": "STREAMS", + "keys": "mystream writers 0-0", + "block": "BLOCK", + "millisecond": "1000", + "stream_id": "0-0", + }, + ) + + +def test_xreadgroup(judge_command): + judge_command( + "XREADGROUP GROUP mygroup1 Bob COUNT 1 BLOCK 100 NOACK STREAMS key1 1 key2 2", + { + "command": "XREADGROUP", + "stream_group": "GROUP", + "group": "mygroup1", + "consumer": "Bob", + "count_const": "COUNT", + "count": "1", + "block": "BLOCK", + "millisecond": "100", + "noack": "NOACK", + "streams": "STREAMS", + "keys": "key1 1 key2", + "stream_id": "2", + }, + ) + judge_command( + "XREADGROUP GROUP mygroup1 Bob STREAMS key1 1 key2 2", + { + "command": "XREADGROUP", + "stream_group": "GROUP", + "group": "mygroup1", + "consumer": "Bob", + "streams": "STREAMS", + "keys": "key1 1 key2", + "stream_id": "2", + }, + ) + + judge_command("XREADGROUP GROUP group consumer", None) diff --git a/tests/unittests/command_parse/test_string_parse.py b/tests/unittests/command_parse/test_string_parse.py new file mode 100644 index 0000000..df56b25 --- /dev/null +++ b/tests/unittests/command_parse/test_string_parse.py @@ -0,0 +1,345 @@ +def test_set(judge_command): + judge_command("SET abc bar", {"command": "SET", "key": "abc", "value": "bar"}) + judge_command( + "SET abc bar EX 10", + { + "command": "SET", + "key": "abc", + "value": "bar", + "expiration": "EX", + "millisecond": "10", + }, + ) + judge_command( + "SET abc bar px 10000", + { + "command": "SET", + "key": "abc", + "value": "bar", + "expiration": "px", + "millisecond": "10000", + }, + ) + judge_command( + "SET abc bar px 10000 nx", + { + "command": "SET", + "key": "abc", + "value": "bar", + "expiration": "px", + "millisecond": "10000", + "condition": "nx", + }, + ) + judge_command( + "SET abc bar px 10000 XX", + { + "command": "SET", + "key": "abc", + "value": "bar", + "expiration": "px", + "millisecond": "10000", + "condition": "XX", + }, + ) + judge_command( + "SET abc bar XX px 10000", + { + "command": "SET", + "key": "abc", + "value": "bar", + "expiration": "px", + "millisecond": "10000", + "condition": "XX", + }, + ) + judge_command( + "SET abc bar XX", + {"command": "SET", "key": "abc", "value": "bar", "condition": "XX"}, + ) + # keepttl + judge_command( + "SET abc bar XX keepttl", + { + "command": "SET", + "key": "abc", + "value": "bar", + "condition": "XX", + "keepttl": "keepttl", + }, + ) + judge_command( + "SET abc bar keepttl XX", + { + "command": "SET", + "key": "abc", + "value": "bar", + "condition": "XX", + "keepttl": "keepttl", + }, + ) + judge_command( + "SET abc bar XX px 10000 KEEPTTL", + { + "command": "SET", + "key": "abc", + "value": "bar", + "expiration": "px", + "millisecond": "10000", + "condition": "XX", + "keepttl": "KEEPTTL", + }, + ) + + +def test_append(judge_command): + judge_command("append foo bar", {"command": "append", "key": "foo", "value": "bar"}) + judge_command( + "APPEND foo 'bar'", {"command": "APPEND", "key": "foo", "value": "'bar'"} + ) + judge_command("APPEND foo", None) + + +def test_bitcount(judge_command): + judge_command("bitcount foo", {"command": "bitcount", "key": "foo"}) + judge_command( + "bitcount foo 1 5", + {"command": "bitcount", "key": "foo", "start": "1", "end": "5"}, + ) + judge_command( + "bitcount foo 1 -5", + {"command": "bitcount", "key": "foo", "start": "1", "end": "-5"}, + ) + judge_command( + "bitcount foo -2 -1", + {"command": "bitcount", "key": "foo", "start": "-2", "end": "-1"}, + ) + judge_command("bitcount foo -2", None) + + +def test_getrange(judge_command): + judge_command("getrange foo", None) + judge_command( + "getrange foo 1 5", + {"command": "getrange", "key": "foo", "start": "1", "end": "5"}, + ) + judge_command( + "getrange foo 1 -5", + {"command": "getrange", "key": "foo", "start": "1", "end": "-5"}, + ) + judge_command( + "getrange foo -2 -1", + {"command": "getrange", "key": "foo", "start": "-2", "end": "-1"}, + ) + judge_command("getrange foo -2", None) + + +def test_get_set(judge_command): + judge_command("GETSET abc bar", {"command": "GETSET", "key": "abc", "value": "bar"}) + + +def test_incr(judge_command): + judge_command("INCR foo", {"command": "INCR", "key": "foo"}) + judge_command("INCR", None) + judge_command("INCR foo 1", None) + + +def test_incr_by(judge_command): + judge_command("INCRBY foo", None) + judge_command("INCRBY", None) + judge_command("INCRBY foo 1", {"command": "INCRBY", "key": "foo", "delta": "1"}) + judge_command("INCRBY foo 200", {"command": "INCRBY", "key": "foo", "delta": "200"}) + judge_command("INCRBY foo -21", {"command": "INCRBY", "key": "foo", "delta": "-21"}) + + +def test_decr(judge_command): + judge_command("DECR foo", {"command": "DECR", "key": "foo"}) + judge_command("DECR", None) + judge_command("DECR foo 1", None) + + +def test_decr_by(judge_command): + judge_command("DECRBY foo", None) + judge_command("DECRBY", None) + judge_command("DECRBY foo 1", {"command": "DECRBY", "key": "foo", "delta": "1"}) + judge_command("DECRBY foo 200", {"command": "DECRBY", "key": "foo", "delta": "200"}) + judge_command("DECRBY foo -21", {"command": "DECRBY", "key": "foo", "delta": "-21"}) + + +def test_command_set_range(judge_command): + judge_command( + "SETRANGE foo 10 bar", + {"command": "SETRANGE", "key": "foo", "offset": "10", "value": "bar"}, + ) + judge_command("SETRANGE foo bar", None) + judge_command( + "SETRANGE Redis 10 'hello world'", + { + "command": "SETRANGE", + "key": "Redis", + "offset": "10", + "value": "'hello world'", + }, + ) + + +def test_command_set_ex(judge_command): + judge_command( + "SETEX key 10 value", + {"command": "SETEX", "key": "key", "second": "10", "value": "value"}, + ) + judge_command("SETEX foo 10", None) + judge_command( + "setex Redis 10 'hello world'", + {"command": "setex", "key": "Redis", "second": "10", "value": "'hello world'"}, + ) + + +def test_command_setbit(judge_command): + judge_command( + "SETBIT key 10 0", + {"command": "SETBIT", "key": "key", "offset": "10", "bit": "0"}, + ) + judge_command( + "SETBIT foo 10 1", + {"command": "SETBIT", "key": "foo", "offset": "10", "bit": "1"}, + ) + judge_command("SETBIT foo 10 10", None) + judge_command("SETBIT foo 10 abc", None) + judge_command("SETBIT foo 10", None) + judge_command("SETBIT foo", None) + + +def test_command_getbit(judge_command): + judge_command("GETBIT key 10", {"command": "GETBIT", "key": "key", "offset": "10"}) + judge_command("GETBIT foo 0", {"command": "GETBIT", "key": "foo", "offset": "0"}) + judge_command("GETBIT foo -1", None) + judge_command("SETBIT foo abc", None) + judge_command("SETBIT foo", None) + + +def test_command_incrbyfloat(judge_command): + judge_command("INCRBYFLOAT key", None) + judge_command( + "INCRBYFLOAT key 1.1", {"command": "INCRBYFLOAT", "key": "key", "float": "1.1"} + ) + judge_command( + "INCRBYFLOAT key .1", {"command": "INCRBYFLOAT", "key": "key", "float": ".1"} + ) + judge_command( + "INCRBYFLOAT key 1.", {"command": "INCRBYFLOAT", "key": "key", "float": "1."} + ) + judge_command( + "INCRBYFLOAT key 5.0e3", + {"command": "INCRBYFLOAT", "key": "key", "float": "5.0e3"}, + ) + judge_command( + "INCRBYFLOAT key -5.0e3", + {"command": "INCRBYFLOAT", "key": "key", "float": "-5.0e3"}, + ) + + +def test_command_mget(judge_command): + judge_command("mget foo bar", {"command": "mget", "keys": "foo bar"}) + + +def test_mset(judge_command): + judge_command("mset foo bar", {"command": "mset", "key": "foo", "value": "bar"}) + judge_command( + "mset foo bar hello world", + {"command": "mset", "key": "hello", "value": "world"}, + ) + + +def test_psetex(judge_command): + judge_command( + "psetex foo 1000 bar", + {"command": "psetex", "key": "foo", "value": "bar", "millisecond": "1000"}, + ) + judge_command("psetex foo bar", None) + + +def test_bitop(judge_command): + judge_command( + "BITOP AND dest key1 key2", + {"command": "BITOP", "operation": "AND", "key": "dest", "keys": "key1 key2"}, + ) + judge_command( + "BITOP AND dest key1", + {"command": "BITOP", "operation": "AND", "key": "dest", "keys": "key1"}, + ) + judge_command("BITOP AND dest", None) + + +def test_bitpos(judge_command): + judge_command( + "BITPOS mykey 1 3 5", + {"command": "BITPOS", "key": "mykey", "bit": "1", "start": "3", "end": "5"}, + ) + judge_command("BITPOS mykey 1", {"command": "BITPOS", "key": "mykey", "bit": "1"}) + judge_command( + "BITPOS mykey 1 3", + {"command": "BITPOS", "key": "mykey", "bit": "1", "start": "3"}, + ) + + +def test_bitfield(judge_command): + judge_command( + "BITFIELD mykey INCRBY i5 100 1 GET u4 0", + { + "command": "BITFIELD", + "key": "mykey", + "incrby": "INCRBY", + "inttype": ["i5", "u4"], + "offset": ["100", "0"], + "value": "1", + "get": "GET", + }, + ) + judge_command( + "BITFIELD mystring SET i8 #0 100", + { + "command": "BITFIELD", + "key": "mystring", + "set": "SET", + "inttype": "i8", + "offset": "#0", + "value": "100", + }, + ) + judge_command( + "BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1", + { + "command": "BITFIELD", + "key": "mykey", + "incrby": "incrby", + "inttype": "u2", + "offset": "102", + "value": "1", + "overflow": "OVERFLOW", + "overflow_option": "SAT", + }, + ) + + +def test_stralgo(judge_command): + judge_command( + "STRALGO LCS STRINGS ohmytext mynewtext", + { + "command": "STRALGO", + "str_algo": "LCS", + "strings_const": "STRINGS", + "values": "ohmytext mynewtext", + }, + ) + + # Due to redis' command design, this can't be fix in any ways. + judge_command( + "STRALGO LCS STRINGS ohmytext mynewtext LEN", + { + "command": "STRALGO", + "str_algo": "LCS", + "strings_const": "STRINGS", + "values": "ohmytext mynewtext LEN", + }, + ) |