diff --git a/.gitignore b/.gitignore
index 8bf3b7d..c6b1494 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.idea
test.json
venv
-html
\ No newline at end of file
+html
+__pycache__
\ No newline at end of file
diff --git a/cts.json b/cts.json
index 8b7ee0b..03c4da9 100644
--- a/cts.json
+++ b/cts.json
@@ -1904,7 +1904,7 @@
"two", "2",
"one", "3"
]
- ],
+ ],
"since": "1.2.0"
},
@@ -3183,7 +3183,7 @@
"result": [
"OK",
[
- "matches",
+ "matches",
[
[
[1,1],
@@ -3210,7 +3210,7 @@
"result": [
"OK",
[
- "matches",
+ "matches",
[
[
[1,1],
@@ -3237,7 +3237,7 @@
"result": [
"OK",
[
- "matches",
+ "matches",
[
[
[1,1],
@@ -3898,7 +3898,7 @@
],
"since": "2.8.7"
},
-
+
{
"name": "bitpos with BYTE / BIT",
"command": [
@@ -5114,17 +5114,275 @@
],
"since": "2.2.0"
},
+
+ {
+ "name": "eval command",
+ "command": [
+ "eval return 0 hello"
+ ],
+ "result": [
+ null
+ ],
+ "since": "2.6.0"
+ },
+
+ {
+ "name": "eval_ro command",
+ "command": [
+ "eval_ro return 0 hello"
+ ],
+ "result": [
+ null
+ ],
+ "since": "7.0.0"
+ },
+
+ {
+ "name": "evalsha command",
+ "command": [
+ "script load return",
+ "evalsha 63143b6f8007b98c53ca2149822777b3566f9241 0",
+ "script flush"
+ ],
+ "result": [
+ "63143b6f8007b98c53ca2149822777b3566f9241",
+ null,
+ "True"
+ ],
+ "since": "2.6.0"
+ },
+
+ {
+ "name": "evalsha_ro command",
+ "command": [
+ "script load return",
+ "evalsha_ro 63143b6f8007b98c53ca2149822777b3566f9241 0",
+ "script flush"
+ ],
+ "result": [
+ "63143b6f8007b98c53ca2149822777b3566f9241",
+ null,
+ "True"
+ ],
+ "since": "7.0.0"
+ },
+
+ {
+ "name": "fcall command",
+ "command": [
+ "function flush",
+ "function load \"#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)\"",
+ "fcall myfunc 0 hello",
+ "function flush"
+ ],
+ "result": [
+ "OK",
+ "mylib",
+ "hello",
+ "OK"
+ ],
+ "since": "7.0.0",
+ "command_split": true
+ },
+
+ {
+ "name": "fcall_ro command",
+ "command": [
+ "function flush",
+ "function load \"#!lua name=mylib \n local function ret(keys, args) return args[1] end \n redis.register_function{function_name='ret', callback=ret, flags={ 'no-writes' }}\"",
+ "fcall_ro ret 0 hello",
+ "function flush"
+ ],
+ "result": [
+ "OK",
+ "mylib",
+ "hello",
+ "OK"
+ ],
+ "since": "7.0.0",
+ "command_split": true
+ },
+
+ {
+ "name": "function delete command",
+ "command": [
+ "function flush",
+ "function load \"#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)\"",
+ "function delete mylib",
+ "function flush"
+ ],
+ "result": [
+ "OK",
+ "mylib",
+ "OK",
+ "OK"
+ ],
+ "since": "7.0.0",
+ "command_split": true
+ },
+
+ {
+ "name": "function flush command",
+ "command": [
+ "function flush"
+ ],
+ "result": [
+ "True"
+ ],
+ "since": "7.0.0"
+ },
+
+
+ {
+ "name": "function list command",
+ "command": [
+ "function flush",
+ "function load \"#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)\"",
+ "function list",
+ "function flush"
+ ],
+ "result": [
+ "OK",
+ "mylib",
+ [
+ [
+ "library_name", "mylib", "engine", "LUA", "functions",
+ [
+ [
+ "name", "myfunc", "description", null, "flags",
+ []
+ ]
+ ]
+ ]
+ ],
+ "OK"
+ ],
+ "since": "7.0.0",
+ "command_split": true
+ },
+
{
"name": "function load command",
"command": [
"function flush",
- "function load \"#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)\""
+ "function load \"#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)\"",
+ "fcall myfunc 0 hello",
+ "function flush"
],
"result": [
"OK",
- "mylib"
+ "mylib",
+ "hello",
+ "OK"
],
"since": "7.0.0",
"command_split": true
+ },
+
+ {
+ "name": "function restore command",
+ "command": [
+ "function flush",
+ "function restore \"\\xf5\\xc3@X@]\\x1f#!lua name=mylib \\n redis.registe\\rr_function('my@\\x0b\\x02', @\\x06`\\x12\\nkeys, args) 6\\x03turn`\\x0c\\a[1] end)\\n\\x00q\\xee\\xf6b\\xe9$\\xbaN\" flush"
+ ],
+ "result": [
+ "OK",
+ "OK"
+ ],
+ "since": "7.0.0",
+ "command_split": true,
+ "command_binary": true
+ },
+
+ {
+ "name": "function stats command",
+ "command": [
+ "function flush",
+ "function stats"
+ ],
+ "result": [
+ "True",
+ [
+ "running_script", null,
+ "engines",
+ [
+ "LUA",
+ [
+ "libraries_count", 0,
+ "functions_count", 0
+ ]
+ ]
+ ]
+ ],
+ "since": "7.0.0"
+ },
+
+ {
+ "name": "script exists command",
+ "command": [
+ "script load return",
+ "script exists 63143b6f8007b98c53ca2149822777b3566f9241",
+ "script flush"
+ ],
+ "result": [
+ "63143b6f8007b98c53ca2149822777b3566f9241",
+ [
+ 1
+ ],
+ "True"
+ ],
+ "since": "2.6.0"
+ },
+
+ {
+ "name": "script flush command",
+ "command": [
+ "script load return",
+ "script flush"
+ ],
+ "result": [
+ "63143b6f8007b98c53ca2149822777b3566f9241",
+ "True"
+ ],
+ "since": "2.6.0"
+ },
+
+ {
+ "name": "script flush with sync",
+ "command": [
+ "script load return",
+ "script flush sync"
+ ],
+ "result": [
+ "63143b6f8007b98c53ca2149822777b3566f9241",
+ "OK"
+ ],
+ "since": "6.2.0"
+ },
+
+ {
+ "name": "script flush with async",
+ "command": [
+ "script load return",
+ "script flush async"
+ ],
+ "result": [
+ "63143b6f8007b98c53ca2149822777b3566f9241",
+ "OK"
+ ],
+ "since": "6.2.0"
+ },
+
+ {
+ "name": "script load command",
+ "command": [
+ "script load return",
+ "script flush"
+ ],
+ "result": [
+ "63143b6f8007b98c53ca2149822777b3566f9241",
+ "True"
+ ],
+ "since": "2.6.0"
}
]
diff --git a/redis_compatibility_test.py b/redis_compatibility_test.py
index baaaf79..cfa52f2 100644
--- a/redis_compatibility_test.py
+++ b/redis_compatibility_test.py
@@ -104,7 +104,7 @@ def trans_result_to_bytes(result):
return result
-def trans_cmd(test, cmd):
+def trans_cmd_to_binary(test, cmd):
if 'command_binary' in test:
array = bytearray()
i = 0
@@ -137,21 +137,28 @@ def trans_cmd(test, cmd):
array.append(ord(cmd[i]))
i += 1
return bytes(array)
- elif 'command_split' in test:
+ else:
+ return cmd
+
+
+def split_cmd_as_list(test, cmd):
+ if 'command_split' in test:
# split command by ""
# input: 'hello "world of python" example'
# output: ['hello', 'world of python', 'example']
parts = []
in_quote = False
- current_part = ''
+ current_part = b''
for char in cmd:
- if char == '"':
+ # If command_binary is true, then char is `int`, otherwise char is str.
+ byte = ord(char) if isinstance(char, str) else char
+ if byte == ord('"'):
in_quote = not in_quote
- elif char == ' ' and not in_quote:
+ elif byte == ord(' ') and not in_quote:
parts.append(current_part)
- current_part = ''
+ current_part = b''
else:
- current_part += char
+ current_part += char.encode() if isinstance(char, str) else bytes([char])
parts.append(current_part)
return parts
else:
@@ -190,11 +197,12 @@ def run_test(test):
trans_result_to_bytes(result)
try:
for idx, cmd in enumerate(command):
- tcmd = trans_cmd(test, cmd)
- if (isinstance(tcmd, list)):
- ret = trans_result_to_bytes(r.execute_command(*trans_cmd(test, cmd)))
+ cmd = trans_cmd_to_binary(test, cmd)
+ tcmd = split_cmd_as_list(test, cmd)
+ if isinstance(tcmd, list):
+ ret = trans_result_to_bytes(r.execute_command(*tcmd))
else:
- ret = trans_result_to_bytes(r.execute_command(trans_cmd(test, cmd)))
+ ret = trans_result_to_bytes(r.execute_command(tcmd))
if 'sort_result' in test and isinstance(result[idx], list):
sort_nested_list(ret)
sort_nested_list(result[idx])
@@ -223,7 +231,7 @@ def generate_html_report(logdir, configs):
html = open(filepath, "w")
html.write("This page is automatically generated by compatibility-test-suite-for-redis"
- " to show the compatibility of the following Redis-Like systems and different versions of Redis.
")
+ "to show the compatibility of the following Redis-Like systems and different versions of Redis.
")
html.write("