diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c98d5d..fe6755e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,11 +1,17 @@ name: CI -on: [ push, pull_request ] +on: + push: + branches: [ v4 ] + pull_request: + branches: [ v4 ] + workflow_dispatch: jobs: black-box-test: runs-on: ubuntu-latest strategy: + max-parallel: 1 matrix: redis-version: [ "2.8", "3.0", "4.0", "5.0", "6.0", "7.0" ] fail-fast: false diff --git a/internal/reader/scan_cluster_reader.go b/internal/reader/scan_cluster_reader.go index 65853ec..3a3f115 100644 --- a/internal/reader/scan_cluster_reader.go +++ b/internal/reader/scan_cluster_reader.go @@ -17,12 +17,9 @@ func NewScanClusterReader(opts *ScanReaderOptions) Reader { rd := &scanClusterReader{} for _, address := range addresses { - rd.readers = append(rd.readers, NewScanStandaloneReader(&ScanReaderOptions{ - Address: address, - Username: opts.Username, - Password: opts.Password, - Tls: opts.Tls, - })) + theOpts := *opts + theOpts.Address = address + rd.readers = append(rd.readers, NewScanStandaloneReader(&theOpts)) } return rd } diff --git a/internal/reader/sync_cluster_reader.go b/internal/reader/sync_cluster_reader.go index 43fe82f..0a98be5 100644 --- a/internal/reader/sync_cluster_reader.go +++ b/internal/reader/sync_cluster_reader.go @@ -21,12 +21,9 @@ func NewSyncClusterReader(opts *SyncReaderOptions) Reader { } rd := &syncClusterReader{} for _, address := range addresses { - rd.readers = append(rd.readers, NewSyncStandaloneReader(&SyncReaderOptions{ - Address: address, - Username: opts.Username, - Password: opts.Password, - Tls: opts.Tls, - })) + theOpts := *opts + theOpts.Address = address + rd.readers = append(rd.readers, NewSyncStandaloneReader(&theOpts)) } return rd } diff --git a/test.sh b/test.sh index 3edc590..91039c6 100755 --- a/test.sh +++ b/test.sh @@ -6,4 +6,4 @@ go test ./... -v # black box test cd tests/ -pybbt cases \ No newline at end of file +pybbt cases --verbose --flags modules \ No newline at end of file diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..e9f6cc2 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,13 @@ +本项目使用 pybbt 工具进行黑盒测试。pybbt 是一个基于 Python 的工具,简化了软件的黑盒测试过程。要运行测试用例,请执行以下命令: + +```bash +pybbt cases --verbose --flags modules +``` +该命令将以详细日志记录的方式运行 cases 目录中的测试用例,并向测试用例传递 modules 标志。 + +如果本地没有安装 modules,可以不起用 modules 标志,这样就会跳过需要 modules 的测试用例: +```bash +pybbt cases --verbose +``` + +更多关于 pybbt 的信息、安装说明和用法示例,请参阅完整的文档: https://pypi.org/project/pybbt/ \ No newline at end of file diff --git a/tests/helpers/commands/tair_hash.py b/tests/helpers/commands/tair_hash.py index d47abcf..99d8802 100644 --- a/tests/helpers/commands/tair_hash.py +++ b/tests/helpers/commands/tair_hash.py @@ -1,8 +1,8 @@ import pybbt from helpers.commands.checker import Checker +from helpers.constant import REDIS_SERVER_MODULES_ENABLED from helpers.redis import Redis -from helpers.constant import REDIS_SERVER_VERSION class TairHashChecker(Checker): @@ -12,22 +12,23 @@ class TairHashChecker(Checker): self.cnt = 0 def add_data(self, r: Redis, cross_slots_cmd: bool): - if REDIS_SERVER_VERSION < 5.0: + if not REDIS_SERVER_MODULES_ENABLED: return + p = r.pipeline() # different parameters type - p.execute_command("EXHSET",f"{self.PREFIX}_{self.cnt}", "field", "value") - p.execute_command("EXHSET",f"{self.PREFIX}_{self.cnt}_ABS", "field_abs", "value_abs", "ABS", 2) - p.execute_command("EXHSET",f"{self.PREFIX}_{self.cnt}_EX", "field_ex", "value_ex", "EX", 20000) + p.execute_command("EXHSET", f"{self.PREFIX}_{self.cnt}", "field", "value") + p.execute_command("EXHSET", f"{self.PREFIX}_{self.cnt}_ABS", "field_abs", "value_abs", "ABS", 2) + p.execute_command("EXHSET", f"{self.PREFIX}_{self.cnt}_EX", "field_ex", "value_ex", "EX", 20000) # different key # different field - p.execute_command("EXHSET",f"{self.PREFIX}_{self.cnt}_ALL_01", "field_all_01", "value_all_01", "EX", 20000, "ABS", 2) - p.execute_command("EXHSET",f"{self.PREFIX}_{self.cnt}_ALL_01", "field_all_02", "value_all_02", "EX", 20000, "ABS", 3) + p.execute_command("EXHSET", f"{self.PREFIX}_{self.cnt}_ALL_01", "field_all_01", "value_all_01", "EX", 20000, "ABS", 2) + p.execute_command("EXHSET", f"{self.PREFIX}_{self.cnt}_ALL_01", "field_all_02", "value_all_02", "EX", 20000, "ABS", 3) + + p.execute_command("EXHSET", f"{self.PREFIX}_{self.cnt}_ALL_02", "field_all_01", "value_all_01", "EX", 20000, "ABS", 2) + p.execute_command("EXHSET", f"{self.PREFIX}_{self.cnt}_ALL_02", "field_all_02", "value_all_02", "EX", 20000, "ABS", 3) - p.execute_command("EXHSET",f"{self.PREFIX}_{self.cnt}_ALL_02", "field_all_01", "value_all_01", "EX", 20000, "ABS", 2) - p.execute_command("EXHSET",f"{self.PREFIX}_{self.cnt}_ALL_02", "field_all_02", "value_all_02", "EX", 20000, "ABS", 3) - ret = p.execute() # pybbt.ASSERT_EQ(ret, [b"1", b"1", b"1", b"1",b"1", b"1",b"1"]) pybbt.ASSERT_EQ(ret, [1, 1, 1, 1, 1, 1, 1]) @@ -35,21 +36,22 @@ class TairHashChecker(Checker): self.cnt += 1 def check_data(self, r: Redis, cross_slots_cmd: bool): - if REDIS_SERVER_VERSION < 5.0: + if not REDIS_SERVER_MODULES_ENABLED: return + for i in range(self.cnt): p = r.pipeline() - p.execute_command("EXHGET",f"{self.PREFIX}_{i}", "field") - p.execute_command("EXHGET",f"{self.PREFIX}_{i}_ABS", "field_abs") - p.execute_command("EXHGET",f"{self.PREFIX}_{i}_EX", "field_ex") + p.execute_command("EXHGET", f"{self.PREFIX}_{i}", "field") + p.execute_command("EXHGET", f"{self.PREFIX}_{i}_ABS", "field_abs") + p.execute_command("EXHGET", f"{self.PREFIX}_{i}_EX", "field_ex") + + p.execute_command("EXHGET", f"{self.PREFIX}_{i}_ALL_01", "field_all_01") + p.execute_command("EXHGET", f"{self.PREFIX}_{i}_ALL_01", "field_all_02") - p.execute_command("EXHGET",f"{self.PREFIX}_{i}_ALL_01", "field_all_01") - p.execute_command("EXHGET",f"{self.PREFIX}_{i}_ALL_01", "field_all_02") + p.execute_command("EXHGET", f"{self.PREFIX}_{i}_ALL_02", "field_all_01") + p.execute_command("EXHGET", f"{self.PREFIX}_{i}_ALL_02", "field_all_02") - p.execute_command("EXHGET",f"{self.PREFIX}_{i}_ALL_02", "field_all_01") - p.execute_command("EXHGET",f"{self.PREFIX}_{i}_ALL_02", "field_all_02") - ret = p.execute() # 需要确定一下如果一个命令返回多个值是如何封装的 - pybbt.ASSERT_EQ(ret, [b"value", b"value_abs", b"value_ex", b"value_all_01", b"value_all_02", b"value_all_01", b"value_all_02",]) \ No newline at end of file + pybbt.ASSERT_EQ(ret, [b"value", b"value_abs", b"value_ex", b"value_all_01", b"value_all_02", b"value_all_01", b"value_all_02", ]) diff --git a/tests/helpers/commands/tair_string.py b/tests/helpers/commands/tair_string.py index 821d5a3..13a5163 100644 --- a/tests/helpers/commands/tair_string.py +++ b/tests/helpers/commands/tair_string.py @@ -1,8 +1,8 @@ import pybbt from helpers.commands.checker import Checker +from helpers.constant import REDIS_SERVER_MODULES_ENABLED from helpers.redis import Redis -from helpers.constant import REDIS_SERVER_VERSION class TairStringChecker(Checker): @@ -12,32 +12,34 @@ class TairStringChecker(Checker): self.cnt = 0 def add_data(self, r: Redis, cross_slots_cmd: bool): - if REDIS_SERVER_VERSION < 5.0: + if not REDIS_SERVER_MODULES_ENABLED: return + p = r.pipeline() # different parameters type - p.execute_command("EXSET",f"{self.PREFIX}_{self.cnt}_ABS", "abs_value", "VER",2) - p.execute_command("EXSET",f"{self.PREFIX}_{self.cnt}_FLAGS", "flags_value", "FLAGS", 2) - p.execute_command("Exset",f"{self.PREFIX}_{self.cnt}_EX", "ex_value", "EX", 20000) + p.execute_command("EXSET", f"{self.PREFIX}_{self.cnt}_ABS", "abs_value", "VER", 2) + p.execute_command("EXSET", f"{self.PREFIX}_{self.cnt}_FLAGS", "flags_value", "FLAGS", 2) + p.execute_command("Exset", f"{self.PREFIX}_{self.cnt}_EX", "ex_value", "EX", 20000) # different key - p.execute_command("Exset",f"{self.PREFIX}_{self.cnt}_ALL_01", "all_value_01", "EX", 20000, "ABS", 3, "FLAGS", 4) - p.execute_command("Exset",f"{self.PREFIX}_{self.cnt}_ALL_02", "all_value_02", "EX", 20000, "ABS", 4, "FLAGS", 5) + p.execute_command("Exset", f"{self.PREFIX}_{self.cnt}_ALL_01", "all_value_01", "EX", 20000, "ABS", 3, "FLAGS", 4) + p.execute_command("Exset", f"{self.PREFIX}_{self.cnt}_ALL_02", "all_value_02", "EX", 20000, "ABS", 4, "FLAGS", 5) ret = p.execute() pybbt.ASSERT_EQ(ret, [b"OK", b"OK", b"OK", b"OK", b"OK"]) self.cnt += 1 def check_data(self, r: Redis, cross_slots_cmd: bool): - if REDIS_SERVER_VERSION < 5.0: + if not REDIS_SERVER_MODULES_ENABLED: return + for i in range(self.cnt): p = r.pipeline() - p.execute_command("EXGET",f"{self.PREFIX}_{i}_ABS") - p.execute_command("EXGET",f"{self.PREFIX}_{i}_FLAGS", "WITHFLAGS") - p.execute_command("EXGET",f"{self.PREFIX}_{i}_EX") - p.execute_command("EXGET",f"{self.PREFIX}_{i}_ALL_01", "WITHFLAGS") - p.execute_command("EXGET",f"{self.PREFIX}_{i}_ALL_02", "WITHFLAGS") + p.execute_command("EXGET", f"{self.PREFIX}_{i}_ABS") + p.execute_command("EXGET", f"{self.PREFIX}_{i}_FLAGS", "WITHFLAGS") + p.execute_command("EXGET", f"{self.PREFIX}_{i}_EX") + p.execute_command("EXGET", f"{self.PREFIX}_{i}_ALL_01", "WITHFLAGS") + p.execute_command("EXGET", f"{self.PREFIX}_{i}_ALL_02", "WITHFLAGS") ret = p.execute() pybbt.ASSERT_EQ(ret, [[b"abs_value", 1], [b"flags_value", 1, 2], [b"ex_value", 1], [b"all_value_01", 3, 4], [b"all_value_02", 4, 5]]) diff --git a/tests/helpers/commands/tair_zset.py b/tests/helpers/commands/tair_zset.py index fff80c4..6585884 100644 --- a/tests/helpers/commands/tair_zset.py +++ b/tests/helpers/commands/tair_zset.py @@ -1,8 +1,8 @@ import pybbt from helpers.commands.checker import Checker +from helpers.constant import REDIS_SERVER_MODULES_ENABLED from helpers.redis import Redis -from helpers.constant import REDIS_SERVER_VERSION class TairZsetChecker(Checker): @@ -12,36 +12,38 @@ class TairZsetChecker(Checker): self.cnt = 0 def add_data(self, r: Redis, cross_slots_cmd: bool): - if REDIS_SERVER_VERSION < 5.0: + if not REDIS_SERVER_MODULES_ENABLED: return + p = r.pipeline() # different key # int or float - p.execute_command("EXZADD",f"{self.PREFIX}_{self.cnt}_key01", "1.1#1.2", "mem01","2.2#2.3", "mem02") - p.execute_command("EXZADD",f"{self.PREFIX}_{self.cnt}_key01", "3.3#3.4", "mem03","4.4#4.5", "mem04") - p.execute_command("EXZADD",f"{self.PREFIX}_{self.cnt}_key02", "1.1#1.2", "mem01") - p.execute_command("EXZADD",f"{self.PREFIX}_{self.cnt}_key02", "2.2#2.3", "mem02") + p.execute_command("EXZADD", f"{self.PREFIX}_{self.cnt}_key01", "1.1#1.2", "mem01", "2.2#2.3", "mem02") + p.execute_command("EXZADD", f"{self.PREFIX}_{self.cnt}_key01", "3.3#3.4", "mem03", "4.4#4.5", "mem04") + p.execute_command("EXZADD", f"{self.PREFIX}_{self.cnt}_key02", "1.1#1.2", "mem01") + p.execute_command("EXZADD", f"{self.PREFIX}_{self.cnt}_key02", "2.2#2.3", "mem02") ret = p.execute() pybbt.ASSERT_EQ(ret, [2, 2, 1, 1]) self.cnt += 1 def check_data(self, r: Redis, cross_slots_cmd: bool): - if REDIS_SERVER_VERSION < 5.0: + if not REDIS_SERVER_MODULES_ENABLED: return + for i in range(self.cnt): p = r.pipeline() - p.execute_command("EXZSCORE",f"{self.PREFIX}_{i}_key01", "mem01") - p.execute_command("EXZSCORE",f"{self.PREFIX}_{i}_key01", "mem02") - p.execute_command("EXZSCORE",f"{self.PREFIX}_{i}_key01", "mem03") - p.execute_command("EXZSCORE",f"{self.PREFIX}_{i}_key01", "mem04") - p.execute_command("EXZSCORE",f"{self.PREFIX}_{i}_key02", "mem01") - p.execute_command("EXZSCORE",f"{self.PREFIX}_{i}_key02", "mem02") - + p.execute_command("EXZSCORE", f"{self.PREFIX}_{i}_key01", "mem01") + p.execute_command("EXZSCORE", f"{self.PREFIX}_{i}_key01", "mem02") + p.execute_command("EXZSCORE", f"{self.PREFIX}_{i}_key01", "mem03") + p.execute_command("EXZSCORE", f"{self.PREFIX}_{i}_key01", "mem04") + p.execute_command("EXZSCORE", f"{self.PREFIX}_{i}_key02", "mem01") + p.execute_command("EXZSCORE", f"{self.PREFIX}_{i}_key02", "mem02") + ret = p.execute() - pybbt.ASSERT_EQ(ret, - [b'1.1000000000000001#1.2', - b'2.2000000000000002#2.2999999999999998', b'3.2999999999999998#3.3999999999999999', - b'4.4000000000000004#4.5', b'1.1000000000000001#1.2', - b'2.2000000000000002#2.2999999999999998'] ) + pybbt.ASSERT_EQ(ret, + [b'1.1000000000000001#1.2', + b'2.2000000000000002#2.2999999999999998', b'3.2999999999999998#3.3999999999999999', + b'4.4000000000000004#4.5', b'1.1000000000000001#1.2', + b'2.2000000000000002#2.2999999999999998']) diff --git a/tests/helpers/constant.py b/tests/helpers/constant.py index 46f957a..c6f6279 100644 --- a/tests/helpers/constant.py +++ b/tests/helpers/constant.py @@ -2,14 +2,20 @@ import shutil import subprocess from pathlib import Path -BASE_PATH = f"{Path(__file__).parent.parent.parent.absolute()}" # project path +import pybbt +BASE_PATH = f"{Path(__file__).parent.parent.parent.absolute()}" # project path PATH_REDIS_SHAKE = f"{BASE_PATH}/bin/redis-shake" PATH_REDIS_SERVER = shutil.which('redis-server') + +# REDIS_SERVER_VERSION output = subprocess.check_output(f"{PATH_REDIS_SERVER} --version", shell=True) output_str = output.decode("utf-8") REDIS_SERVER_VERSION = float(output_str.split("=")[1].split(" ")[0][:3]) +# REDIS_SERVER_MODULES_ENABLED +REDIS_SERVER_MODULES_ENABLED = REDIS_SERVER_VERSION >= 5.0 and "modules" in pybbt.get_global_flags() + if __name__ == '__main__': print(BASE_PATH) print(PATH_REDIS_SHAKE) diff --git a/tests/helpers/data_inserter.py b/tests/helpers/data_inserter.py index 504ed1e..0bca3fc 100644 --- a/tests/helpers/data_inserter.py +++ b/tests/helpers/data_inserter.py @@ -1,6 +1,5 @@ -from helpers.commands import SelectChecker, StringChecker, TairStringChecker, TairHashChecker, TairZsetChecker +from helpers.commands import SelectChecker, StringChecker, TairHashChecker, TairStringChecker, TairZsetChecker from helpers.redis import Redis -from helpers.constant import PATH_REDIS_SERVER, REDIS_SERVER_VERSION class DataInserter: @@ -13,7 +12,6 @@ class DataInserter: TairZsetChecker(), ] - def add_data(self, r: Redis, cross_slots_cmd: bool): for checker in self.checkers: checker.add_data(r, cross_slots_cmd) diff --git a/tests/helpers/redis.py b/tests/helpers/redis.py index b90cf7b..aa83bee 100644 --- a/tests/helpers/redis.py +++ b/tests/helpers/redis.py @@ -3,7 +3,7 @@ import time import pybbt import redis -from helpers.constant import PATH_REDIS_SERVER, REDIS_SERVER_VERSION +from helpers.constant import PATH_REDIS_SERVER, REDIS_SERVER_MODULES_ENABLED, REDIS_SERVER_VERSION from helpers.utils.network import get_free_port from helpers.utils.timer import Timer @@ -17,14 +17,12 @@ class Redis: self.port = get_free_port() self.dir = f"{self.case_ctx.dir}/redis_{self.port}" args.extend(["--port", str(self.port)]) - - if REDIS_SERVER_VERSION > 4.0: + + if REDIS_SERVER_MODULES_ENABLED: args.extend(["--loadmodule", "tairstring_module.so"]) args.extend(["--loadmodule", "tairhash_module.so"]) args.extend(["--loadmodule", "tairzset_module.so"]) - self.server = pybbt.Launcher(args=[PATH_REDIS_SERVER] + args, work_dir=self.dir) - else: - self.server = pybbt.Launcher(args=[PATH_REDIS_SERVER] + args, work_dir=self.dir) + self.server = pybbt.Launcher(args=[PATH_REDIS_SERVER] + args, work_dir=self.dir) self._wait_start() self.client = redis.Redis(host=self.host, port=self.port) @@ -66,4 +64,4 @@ class Redis: return self.client.info()["cluster_enabled"] def dbsize(self): - return self.client.dbsize() \ No newline at end of file + return self.client.dbsize()