Support cluster test
This commit is contained in:
parent
90ae83d20f
commit
73284e3bca
|
@ -13,7 +13,7 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
- name: clone and build redis
|
||||
run: |
|
||||
sudo apt-get install git
|
||||
sudo apt-get install git ruby
|
||||
git clone https://github.com/redis/redis
|
||||
cd redis
|
||||
git checkout 4.0
|
||||
|
@ -23,6 +23,13 @@ jobs:
|
|||
run: |
|
||||
./redis/src/redis-server &
|
||||
|
||||
- name: start redis cluster
|
||||
run: |
|
||||
sudo gem install redis
|
||||
cd redis/utils/create-cluster
|
||||
./create-cluster start
|
||||
echo yes|./create-cluster create
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
@ -38,3 +45,11 @@ jobs:
|
|||
run: |
|
||||
cat test.result
|
||||
grep -q "This is failed tests for" test.result && exit -1 || exit 0
|
||||
|
||||
- name: run cluster test
|
||||
run: python redis_compatibility_test.py --testfile cts.json --port 30001 --specific-version 4.0.0 --cluster --show-failed > cluster.result
|
||||
|
||||
- name: check cluster fail tests
|
||||
run: |
|
||||
cat cluster.result
|
||||
grep -q "This is failed tests for" cluster.result && exit -1 || exit 0
|
||||
|
|
|
@ -23,6 +23,12 @@ jobs:
|
|||
run: |
|
||||
./redis/src/redis-server &
|
||||
|
||||
- name: start redis cluster
|
||||
run: |
|
||||
cd redis/utils/create-cluster
|
||||
./create-cluster start
|
||||
echo yes|./create-cluster create
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
@ -38,3 +44,11 @@ jobs:
|
|||
run: |
|
||||
cat test.result
|
||||
grep -q "This is failed tests for" test.result && exit -1 || exit 0
|
||||
|
||||
- name: run cluster test
|
||||
run: python redis_compatibility_test.py --testfile cts.json --port 30001 --specific-version 5.0.0 --cluster --show-failed > cluster.result
|
||||
|
||||
- name: check cluster fail tests
|
||||
run: |
|
||||
cat cluster.result
|
||||
grep -q "This is failed tests for" cluster.result && exit -1 || exit 0
|
|
@ -23,6 +23,12 @@ jobs:
|
|||
run: |
|
||||
./redis/src/redis-server &
|
||||
|
||||
- name: start redis cluster
|
||||
run: |
|
||||
cd redis/utils/create-cluster
|
||||
./create-cluster start
|
||||
echo yes|./create-cluster create
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
@ -38,3 +44,11 @@ jobs:
|
|||
run: |
|
||||
cat test.result
|
||||
grep -q "This is failed tests for" test.result && exit -1 || exit 0
|
||||
|
||||
- name: run cluster test
|
||||
run: python redis_compatibility_test.py --testfile cts.json --port 30001 --specific-version 6.0.0 --cluster --show-failed > cluster.result
|
||||
|
||||
- name: check cluster fail tests
|
||||
run: |
|
||||
cat cluster.result
|
||||
grep -q "This is failed tests for" cluster.result && exit -1 || exit 0
|
|
@ -23,6 +23,12 @@ jobs:
|
|||
run: |
|
||||
./redis/src/redis-server &
|
||||
|
||||
- name: start redis cluster
|
||||
run: |
|
||||
cd redis/utils/create-cluster
|
||||
./create-cluster start
|
||||
echo yes|./create-cluster create
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
@ -38,3 +44,11 @@ jobs:
|
|||
run: |
|
||||
cat test.result
|
||||
grep -q "This is failed tests for" test.result && exit -1 || exit 0
|
||||
|
||||
- name: run cluster test
|
||||
run: python redis_compatibility_test.py --testfile cts.json --port 30001 --specific-version 6.2.0 --cluster --show-failed > cluster.result
|
||||
|
||||
- name: check cluster fail tests
|
||||
run: |
|
||||
cat cluster.result
|
||||
grep -q "This is failed tests for" cluster.result && exit -1 || exit 0
|
|
@ -23,6 +23,12 @@ jobs:
|
|||
run: |
|
||||
./redis/src/redis-server &
|
||||
|
||||
- name: start redis cluster
|
||||
run: |
|
||||
cd redis/utils/create-cluster
|
||||
./create-cluster start
|
||||
echo yes|./create-cluster create
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
@ -38,3 +44,11 @@ jobs:
|
|||
run: |
|
||||
cat test.result
|
||||
grep -q "This is failed tests for" test.result && exit -1 || exit 0
|
||||
|
||||
- name: run cluster test
|
||||
run: python redis_compatibility_test.py --testfile cts.json --port 30001 --specific-version 7.0.0 --cluster --show-failed > cluster.result
|
||||
|
||||
- name: check cluster fail tests
|
||||
run: |
|
||||
cat cluster.result
|
||||
grep -q "This is failed tests for" cluster.result && exit -1 || exit 0
|
|
@ -23,6 +23,12 @@ jobs:
|
|||
run: |
|
||||
./redis/src/redis-server &
|
||||
|
||||
- name: start redis cluster
|
||||
run: |
|
||||
cd redis/utils/create-cluster
|
||||
./create-cluster start
|
||||
echo yes|./create-cluster create
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
@ -38,3 +44,11 @@ jobs:
|
|||
run: |
|
||||
cat test.result
|
||||
grep -q "This is failed tests for" test.result && exit -1 || exit 0
|
||||
|
||||
- name: run cluster test
|
||||
run: python redis_compatibility_test.py --testfile cts.json --port 30001 --specific-version 7.2.0 --cluster --show-failed > cluster.result
|
||||
|
||||
- name: check cluster fail tests
|
||||
run: |
|
||||
cat cluster.result
|
||||
grep -q "This is failed tests for" cluster.result && exit -1 || exit 0
|
|
@ -22,6 +22,12 @@ jobs:
|
|||
run: |
|
||||
./redis/src/redis-server &
|
||||
|
||||
- name: start redis cluster
|
||||
run: |
|
||||
cd redis/utils/create-cluster
|
||||
./create-cluster start
|
||||
echo yes|./create-cluster create
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
@ -37,3 +43,11 @@ jobs:
|
|||
run: |
|
||||
cat test.result
|
||||
grep -q "This is failed tests for" test.result && exit -1 || exit 0
|
||||
|
||||
- name: run cluster test
|
||||
run: python redis_compatibility_test.py --testfile cts.json --port 30001 --cluster --show-failed > cluster.result
|
||||
|
||||
- name: check cluster fail tests
|
||||
run: |
|
||||
cat cluster.result
|
||||
grep -q "This is failed tests for" cluster.result && exit -1 || exit 0
|
|
@ -22,11 +22,12 @@ optional arguments:
|
|||
--port PORT the redis port
|
||||
--password PASSWORD the redis password
|
||||
--testfile TESTFILE the redis compatibility test cases
|
||||
--specific-version {1.0.0, 2.8.0, 3.2.0, 4.0.0, 5.0.0, 6.0.0, 6.2.0, 7.0.0}
|
||||
--specific-version {1.0.0,2.8.0,3.2.0,4.0.0,5.0.0,6.0.0,6.2.0,7.0.0,7.2.0}
|
||||
the redis version
|
||||
--show-failed show details of failed tests
|
||||
--cluster server is a node of the Redis cluster
|
||||
--ssl open ssl connection
|
||||
--genhtml generate test report in html format
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
|
|
@ -22,6 +22,9 @@ Run the test for compatibility with Redis 6.2.0
|
|||
|
||||
Run the test whether it is compatible with Redis 6.2.0, and print the failure case
|
||||
python3 redis_compatibility_test.py --testfile cts.json --specific-version 6.2.0 --show-failed
|
||||
|
||||
Run the test for redis cluster
|
||||
python3 redis_compatibility_test.py --testfile cts.json --host 127.0.0.1 --port 30001 --cluster
|
||||
"""
|
||||
|
||||
|
||||
|
@ -69,15 +72,6 @@ def report_result():
|
|||
print('\n'.join(str(fail) for fail in t.failed), file=logfile)
|
||||
|
||||
|
||||
def is_equal(left, right):
|
||||
if type(left) is bytes and type(right) is str:
|
||||
return left.decode() == right
|
||||
elif type(left) is str and type(right) is bytes:
|
||||
return left == right.decode()
|
||||
else:
|
||||
return left == right
|
||||
|
||||
|
||||
def test_passed(result):
|
||||
print("passed", file=logfile)
|
||||
result.total += 1
|
||||
|
@ -90,90 +84,75 @@ def test_failed(result, name, e):
|
|||
result.failed.append(FailedTest(name=name, reason=e))
|
||||
|
||||
|
||||
def trans_result_to_bytes(result):
|
||||
if type(result) is str:
|
||||
return result.encode()
|
||||
if type(result) is list:
|
||||
for i in range(len(result)):
|
||||
result[i] = trans_result_to_bytes(result[i])
|
||||
if type(result) is map:
|
||||
for k, v in result.items():
|
||||
result[k.encode()] = trans_result_to_bytes(v)
|
||||
del result[k]
|
||||
if type(result) is bool:
|
||||
return str(result).encode()
|
||||
return result
|
||||
def trans_cmd_to_binary(cmd):
|
||||
array = bytearray()
|
||||
i = 0
|
||||
while i < len(cmd):
|
||||
if cmd[i] == '\\' and cmd[i + 1] == '\\':
|
||||
array.append(92)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == '"':
|
||||
array.append(34)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'n':
|
||||
array.append(10)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'r':
|
||||
array.append(13)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 't':
|
||||
array.append(9)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'a':
|
||||
array.append(7)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'b':
|
||||
array.append(8)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'x':
|
||||
array.append(int(cmd[i + 2], 16) * 16 + int(cmd[i + 3], 16))
|
||||
i += 4
|
||||
else:
|
||||
array.append(ord(cmd[i]))
|
||||
i += 1
|
||||
return bytes(array)
|
||||
|
||||
|
||||
def trans_cmd_to_binary(test, cmd):
|
||||
if 'command_binary' in test:
|
||||
array = bytearray()
|
||||
i = 0
|
||||
while i < len(cmd):
|
||||
if cmd[i] == '\\' and cmd[i + 1] == '\\':
|
||||
array.append(92)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == '"':
|
||||
array.append(34)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'n':
|
||||
array.append(10)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'r':
|
||||
array.append(13)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 't':
|
||||
array.append(9)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'a':
|
||||
array.append(7)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'b':
|
||||
array.append(8)
|
||||
i += 2
|
||||
elif cmd[i] == '\\' and cmd[i + 1] == 'x':
|
||||
array.append(int(cmd[i + 2], 16) * 16 + int(cmd[i + 3], 16))
|
||||
i += 4
|
||||
def split_cmd_as_list(cmd, command_binary):
|
||||
# split command by ""
|
||||
# input: 'hello "world of python" example'
|
||||
# output: ['hello', 'world of python', 'example']
|
||||
parts = []
|
||||
in_quote = False
|
||||
current_part = b'' if command_binary else ''
|
||||
for char in cmd:
|
||||
byte = char if command_binary else ord(char)
|
||||
if byte == ord('"'):
|
||||
in_quote = not in_quote
|
||||
elif byte == ord(' ') and not in_quote:
|
||||
parts.append(current_part)
|
||||
current_part = b'' if command_binary else ''
|
||||
else:
|
||||
if command_binary:
|
||||
current_part += bytes([byte])
|
||||
else:
|
||||
array.append(ord(cmd[i]))
|
||||
i += 1
|
||||
return bytes(array)
|
||||
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 = b''
|
||||
for char in cmd:
|
||||
# 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 byte == ord(' ') and not in_quote:
|
||||
parts.append(current_part)
|
||||
current_part = b''
|
||||
else:
|
||||
current_part += char.encode() if isinstance(char, str) else bytes([char])
|
||||
parts.append(current_part)
|
||||
return parts
|
||||
else:
|
||||
return cmd
|
||||
current_part += char
|
||||
parts.append(current_part)
|
||||
if command_binary:
|
||||
parts[0] = parts[0].decode()
|
||||
return parts
|
||||
|
||||
|
||||
def sort_nested_list(result):
|
||||
nested = False
|
||||
for ele in result:
|
||||
if isinstance(ele, list):
|
||||
ele.sort()
|
||||
nested = True
|
||||
if not nested:
|
||||
result.sort()
|
||||
has_nested_list = False
|
||||
for i in range(len(result)):
|
||||
if isinstance(result[i], list):
|
||||
has_nested_list = True
|
||||
result[i] = sort_nested_list(result[i])
|
||||
if has_nested_list:
|
||||
return result
|
||||
else:
|
||||
return sorted(result)
|
||||
|
||||
|
||||
def run_test(test):
|
||||
|
@ -184,6 +163,14 @@ def run_test(test):
|
|||
print("skipped", file=logfile)
|
||||
return
|
||||
|
||||
# judge tags not match
|
||||
if 'tags' in test:
|
||||
tags = test['tags']
|
||||
if (args.cluster and tags == "standalone") or \
|
||||
(not args.cluster and tags == "cluster"):
|
||||
print("tags skipped", file=logfile)
|
||||
return
|
||||
|
||||
# high version test
|
||||
since = test['since']
|
||||
if args.specific_version and since > args.specific_version:
|
||||
|
@ -195,18 +182,17 @@ def run_test(test):
|
|||
r.flushall()
|
||||
command = test['command']
|
||||
result = test['result']
|
||||
trans_result_to_bytes(result)
|
||||
try:
|
||||
for idx, cmd in enumerate(command):
|
||||
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))
|
||||
if 'command_binary' in test:
|
||||
cmd = trans_cmd_to_binary(cmd)
|
||||
tcmd = split_cmd_as_list(cmd, True)
|
||||
else:
|
||||
ret = trans_result_to_bytes(r.execute_command(tcmd))
|
||||
tcmd = split_cmd_as_list(cmd, False)
|
||||
ret = r.execute_command(*tcmd)
|
||||
if 'sort_result' in test and isinstance(result[idx], list):
|
||||
sort_nested_list(ret)
|
||||
sort_nested_list(result[idx])
|
||||
ret = sort_nested_list(ret)
|
||||
result[idx] = sort_nested_list(result[idx])
|
||||
if result[idx] != ret:
|
||||
test_failed(g_results[since], name, f"expected: {result[idx]}, result: {ret}")
|
||||
return
|
||||
|
@ -319,11 +305,15 @@ def create_client(host, port, password, ssl, cluster):
|
|||
global r
|
||||
if cluster:
|
||||
print(f"connecting to {host}:{port} use cluster client", file=logfile)
|
||||
r = redis.RedisCluster(host=host, port=port, password=password, ssl=ssl)
|
||||
r = redis.RedisCluster(host=host, port=port, password=password, ssl=ssl, decode_responses=True)
|
||||
for _, nodes in dict(r.nodes_manager.slots_cache).items():
|
||||
for node in nodes:
|
||||
node.redis_connection.response_callbacks = {}
|
||||
assert r.ping()
|
||||
else:
|
||||
print(f"connecting to {host}:{port} use standalone client", file=logfile)
|
||||
r = redis.Redis(host=host, port=port, password=password, ssl=ssl)
|
||||
r = redis.Redis(host=host, port=port, password=password, ssl=ssl, decode_responses=True)
|
||||
r.response_callbacks = {}
|
||||
assert r.ping()
|
||||
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
redis>=4.3.4
|
||||
pyyaml>=6.0
|
||||
pyyaml>=6.0
|
||||
dataclasses
|
Loading…
Reference in New Issue