"""使用唯一的本地测试库运行迁移和集成测试,绝不清理原业务库。""" 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", "UPLOAD_DIR": str(root / ".ai" / "isolated-uploads" / database), } 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())