PayrollManagementSystem/scripts/run_isolated_tests.py
liuwenxin 108bf87225 feat(核算)!: 添加 T+ 正式核算与采集托管
补齐源快照、资料预演、正式导入及工资核算的依赖链路。
新增版本化输入、逐段 FIFO、生成锁和结构化当月调整,
并提供默认关闭的周期采集、有限重试及 Windows 托管。

原始客户资料、私有配置及首页改动不纳入本次提交。

BREAKING CHANGE: 升级前需应用新增迁移,并通过
PAYROLL_MAKER_USER_ID 绑定实际工资制作人,否则业务只读。
旧单批次核算默认关闭;历史兼容需显式启用
PAYROLL_ALLOW_LEGACY_CALCULATION。生产启用和真实金额待验收。
2026-11-02 09:42:53 +08:00

52 lines
2.3 KiB
Python

"""使用唯一的本地测试库运行迁移和集成测试,绝不清理原业务库。"""
import os
import argparse
import re
import secrets
import subprocess
import sys
from pathlib import Path
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--reuse-database')
parser.add_argument('--migration-roundtrip', action='store_true')
parsed, test_args = parser.parse_known_args()
if parsed.reuse_database and not re.fullmatch(r'payroll_test_[0-9a-f]{12}', parsed.reuse_database):
raise SystemExit('只允许复用本运行器创建的隔离测试库')
root = Path(__file__).resolve().parents[1]
python = root / "backend/.venv-workbench/Scripts/python.exe"
if not python.exists():
python = Path(sys.executable)
suffix = secrets.token_hex(6)
database, username = parsed.reuse_database or "payroll_test_" + suffix, "pytest_" + suffix
password = secrets.token_urlsafe(30)
sql = ("" if parsed.reuse_database else f"CREATE DATABASE `{database}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ") + f"CREATE USER '{username}'@'%' IDENTIFIED BY '{password}'; GRANT ALL PRIVILEGES ON `{database}`.* TO '{username}'@'%';"
setup = subprocess.run(
["docker", "exec", "-i", "ys-mysql-dev", "sh", "-c", 'export MYSQL_PWD="$MYSQL_ROOT_PASSWORD"; exec mysql -uroot'],
input=sql.encode(), capture_output=True,
)
if setup.returncode:
raise SystemExit("隔离库创建失败,未执行迁移或测试")
env = os.environ | {
"MYSQL_DATABASE": database, "MYSQL_USER": username, "MYSQL_PASSWORD": password,
"PAYROLL_TEST_DATABASE": database, "REDIS_DB": "15", "PYTHONIOENCODING": "utf-8",
}
print("独立测试库:" + database, flush=True)
commands = [["-m", "alembic", "upgrade", "head"]]
if parsed.migration_roundtrip:
commands += [["-m", "alembic", "downgrade", "07b8c9d0e1f2"], ["-m", "alembic", "upgrade", "head"]]
args = test_args
commands.append(["-m", "pytest", *(args or ["tests/integration"]), "-q", "--tb=short"])
for args in commands:
result = subprocess.run([str(python), *args], cwd=root / "backend", env=env)
if result.returncode:
return result.returncode
return 0
if __name__ == "__main__":
raise SystemExit(main())