Support cluster test

This commit is contained in:
bodong.ybd 2023-08-17 19:41:26 +08:00
parent 90ae83d20f
commit 73284e3bca
11 changed files with 1812 additions and 228 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

1749
cts.json

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -1,2 +1,3 @@
redis>=4.3.4
pyyaml>=6.0
pyyaml>=6.0
dataclasses