From b6033c0eda953c819f8b51ca7aefe65799c3384f Mon Sep 17 00:00:00 2001 From: Daz <90372666+Daz-3ux@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:26:40 +0800 Subject: [PATCH] feat: add support for script (#13) feat: add support for script and function Signed-off-by: Pengda Yang Co-authored-by: bodong.ybd --- .gitignore | 3 +- cts.json | 272 +++++++++++++++++++++++++++++++++++- redis_compatibility_test.py | 32 +++-- 3 files changed, 287 insertions(+), 20 deletions(-) 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("") # generate header html.write("")