feat: add support for script (#13)

feat: add support for script and function

Signed-off-by: Pengda Yang <daz-3ux@proton.me>
Co-authored-by: bodong.ybd <bodong.ybd@alibaba-inc.com>
This commit is contained in:
Daz 2023-08-16 17:26:40 +08:00 committed by GitHub
parent 4b0296f02a
commit b6033c0eda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 287 additions and 20 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
.idea .idea
test.json test.json
venv venv
html html
__pycache__

272
cts.json
View File

@ -1904,7 +1904,7 @@
"two", "2", "two", "2",
"one", "3" "one", "3"
] ]
], ],
"since": "1.2.0" "since": "1.2.0"
}, },
@ -3183,7 +3183,7 @@
"result": [ "result": [
"OK", "OK",
[ [
"matches", "matches",
[ [
[ [
[1,1], [1,1],
@ -3210,7 +3210,7 @@
"result": [ "result": [
"OK", "OK",
[ [
"matches", "matches",
[ [
[ [
[1,1], [1,1],
@ -3237,7 +3237,7 @@
"result": [ "result": [
"OK", "OK",
[ [
"matches", "matches",
[ [
[ [
[1,1], [1,1],
@ -3898,7 +3898,7 @@
], ],
"since": "2.8.7" "since": "2.8.7"
}, },
{ {
"name": "bitpos with BYTE / BIT", "name": "bitpos with BYTE / BIT",
"command": [ "command": [
@ -5114,17 +5114,275 @@
], ],
"since": "2.2.0" "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", "name": "function load command",
"command": [ "command": [
"function flush", "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": [ "result": [
"OK", "OK",
"mylib" "mylib",
"hello",
"OK"
], ],
"since": "7.0.0", "since": "7.0.0",
"command_split": true "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"
} }
] ]

View File

@ -104,7 +104,7 @@ def trans_result_to_bytes(result):
return result return result
def trans_cmd(test, cmd): def trans_cmd_to_binary(test, cmd):
if 'command_binary' in test: if 'command_binary' in test:
array = bytearray() array = bytearray()
i = 0 i = 0
@ -137,21 +137,28 @@ def trans_cmd(test, cmd):
array.append(ord(cmd[i])) array.append(ord(cmd[i]))
i += 1 i += 1
return bytes(array) 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 "" # split command by ""
# input: 'hello "world of python" example' # input: 'hello "world of python" example'
# output: ['hello', 'world of python', 'example'] # output: ['hello', 'world of python', 'example']
parts = [] parts = []
in_quote = False in_quote = False
current_part = '' current_part = b''
for char in cmd: 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 in_quote = not in_quote
elif char == ' ' and not in_quote: elif byte == ord(' ') and not in_quote:
parts.append(current_part) parts.append(current_part)
current_part = '' current_part = b''
else: else:
current_part += char current_part += char.encode() if isinstance(char, str) else bytes([char])
parts.append(current_part) parts.append(current_part)
return parts return parts
else: else:
@ -190,11 +197,12 @@ def run_test(test):
trans_result_to_bytes(result) trans_result_to_bytes(result)
try: try:
for idx, cmd in enumerate(command): for idx, cmd in enumerate(command):
tcmd = trans_cmd(test, cmd) cmd = trans_cmd_to_binary(test, cmd)
if (isinstance(tcmd, list)): tcmd = split_cmd_as_list(test, cmd)
ret = trans_result_to_bytes(r.execute_command(*trans_cmd(test, cmd))) if isinstance(tcmd, list):
ret = trans_result_to_bytes(r.execute_command(*tcmd))
else: 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): if 'sort_result' in test and isinstance(result[idx], list):
sort_nested_list(ret) sort_nested_list(ret)
sort_nested_list(result[idx]) sort_nested_list(result[idx])
@ -223,7 +231,7 @@ def generate_html_report(logdir, configs):
html = open(filepath, "w") html = open(filepath, "w")
html.write("This page is automatically generated by <a href=\"https://github.com/tair-opensource/" html.write("This page is automatically generated by <a href=\"https://github.com/tair-opensource/"
"compatibility-test-suite-for-redis\">compatibility-test-suite-for-redis</a>" "compatibility-test-suite-for-redis\">compatibility-test-suite-for-redis</a>"
" to show the compatibility of the following Redis-Like systems and different versions of Redis.<br><br>") "to show the compatibility of the following Redis-Like systems and different versions of Redis.<br><br>")
html.write("<table>") html.write("<table>")
# generate header # generate header
html.write("<thead>") html.write("<thead>")