tradingSystem/scripts/unit_test_guard.py

72 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""单测进程的联网护栏。导入即安装,联网失败即使被捕获,进程也必须失败。
完整隔离入口:python scripts/unit_test_guard.py scripts/test_batch3_units.py。
入口在空临时目录运行测试,只继承系统环境,不读取仓库 .env 或生产参数。
仅供测试使用,生产模块不得导入。
"""
import atexit
import os
from pathlib import Path
import runpy
import sys
import tempfile
import traceback
_violations = []
_ROOT = str(Path(__file__).resolve().parents[1]) + os.sep
def _audit(event, args):
if event in {"socket.connect", "socket.getaddrinfo", "socket.sendto", "socket.sendmsg"}:
# 不输出连接地址或凭据,只保留调用位置。
_violations.append((event, traceback.extract_stack()[:-1]))
raise RuntimeError("单测禁止联网: " + event)
def _finish():
if _violations:
print("\nTEST ISOLATION FAILED: 检测到未替换的外部调用", file=sys.stderr)
try:
for event, stack in _violations[:5]:
print(event, file=sys.stderr)
local = [frame for frame in stack if frame.filename.startswith(_ROOT)]
traceback.print_list(local[-12:] or stack[-12:], file=sys.stderr)
sys.stdout.flush()
sys.stderr.flush()
finally:
os._exit(1) # atexit 里抛异常不会改变进程退出码。
def run_suite(path):
path = Path(path).resolve()
sys.path.insert(0, str(path.parent))
keep = {k: v for k, v in os.environ.items()
if k in {"PATH", "SYSTEMROOT", "LANG", "LC_ALL"}}
keep.update(TZ="Asia/Shanghai", PYTHONDONTWRITEBYTECODE="1")
os.environ.clear()
os.environ.update(keep)
sys.dont_write_bytecode = True
import time
if hasattr(time, "tzset"):
time.tzset()
previous = Path.cwd()
with tempfile.TemporaryDirectory(prefix="pms-unit-") as isolated:
try:
os.chdir(isolated)
sys.argv = [str(path)]
runpy.run_path(str(path), run_name="__main__")
finally:
os.chdir(previous)
if __name__ == "__main__":
if len(sys.argv) != 2:
raise SystemExit("用法: python scripts/unit_test_guard.py 测试文件")
# 独立模块保存护栏状态,不与 runpy 临时使用的 __main__ 共用全局字典。
from unit_test_guard import run_suite
run_suite(sys.argv[1])
else:
sys.addaudithook(_audit)
atexit.register(_finish)