#!/usr/bin/env bash # ===================================================================== # pbl_evidence 测试运行器(发现项 DISC.2) # # 一条命令跑通离线单测,**不需要手工注入 PYTHONPATH**: # bash scripts/run_tests.sh # 等价 python3 -m pytest tests/test_m5a_idempotency.py -v # bash scripts/run_tests.sh tests/test_m5a_idempotency.py -v # bash scripts/run_tests.sh --log /tmp/m5a-pytest.log # PBL_EVIDENCE_TEST_DB=1 bash scripts/run_tests.sh # 打开真实双次采集用例(需测试库) # PBL_EVIDENCE_TEST_DB=1 PBL_EVIDENCE_TEST_TENANT=m5a-demo bash scripts/run_tests.sh # # 想在当前 shell 里**原样**敲 `python3 -m pytest ...`(任务要求的字面命令): # source scripts/activate_test_env.sh && python3 -m pytest tests/test_m5a_idempotency.py -v # # 解释器解析顺序(第一个「能 import pytest」的胜出): # ① $PBL_EVIDENCE_TEST_PYTHON —— 显式指定(CI 用宿主 venv 时走这条) # ② 宿主 python3 —— 若已 pip install pytest / -e .[test](正规长期方案) # ③ 模块测试 venv .venv-test/bin/python —— 缺则自动调 scripts/setup_test_env.sh 引导 # 全部不可用 → exit 3 并打印可执行的修复命令(不静默跳过、不假绿)。 # # 为什么不再用 PYTHONPATH=/.pylibs:那是工作空间私有的临时目录, # 换机器/换角色即失效,且把「环境缺依赖」伪装成「测试通过」,属 DISC.2 根因。 # ===================================================================== set -euo pipefail MODULE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" VENV="${PBL_EVIDENCE_TEST_VENV:-${MODULE_ROOT}/.venv-test}" DEFAULT_TARGET="tests/test_m5a_idempotency.py -v" log() { echo "[run_tests] $*"; } die() { echo "[run_tests][FATAL] $*" >&2; exit "${2:-1}"; } has_pytest() { local py="$1" [ -x "${py}" ] || return 1 "${py}" -c 'import pytest' >/dev/null 2>&1 } cd "${MODULE_ROOT}" # ---- 仓库卫生自检(QC #1 回归防线,不阻断测试,只打印)---- if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then _hyg="$(git check-ignore -q "${VENV#${MODULE_ROOT}/}" && echo ignored || echo NOT-ignored)" _trk="$(git ls-files "${VENV#${MODULE_ROOT}/}" | wc -l | tr -d ' ')" log "仓库卫生: .gitignore=${_hyg} tracked_in_venv=${_trk}(期望 ignored / 0)" [ "${_hyg}" = "ignored" ] || log "[WARN] venv 落点未被 .gitignore 忽略,会把依赖目录提交进版本库" [ "${_trk}" = "0" ] || log "[WARN] venv 内有 ${_trk} 个文件仍被版本跟踪,执行 git rm -r --cached '${VENV#${MODULE_ROOT}/}'" fi # ---- 解析解释器 ---- PY="" for cand in "${PBL_EVIDENCE_TEST_PYTHON:-}" "$(command -v python3 || true)" "${VENV}/bin/python"; do [ -n "${cand}" ] || continue if has_pytest "${cand}"; then PY="${cand}" break fi done if [ -z "${PY}" ]; then log "宿主 python3 与测试 venv 均无 pytest,引导测试环境(scripts/setup_test_env.sh)" bash "${MODULE_ROOT}/scripts/setup_test_env.sh" || die "测试环境引导失败,见上方日志" 3 PY="${VENV}/bin/python" has_pytest "${PY}" || die "引导后仍无法 import pytest(${PY})" 3 fi log "python = ${PY} ($("${PY}" -V 2>&1))" log "pytest = $("${PY}" -m pytest --version 2>&1 | head -1)" log "cwd = ${MODULE_ROOT}" [ "${PBL_EVIDENCE_TEST_DB:-}" = "" ] && \ log "DB 开关 = 未设置(真实双次采集用例 test_double_collect_is_idempotent_with_db 预期 SKIPPED)" || \ log "DB 开关 = PBL_EVIDENCE_TEST_DB=${PBL_EVIDENCE_TEST_DB} tenant=${PBL_EVIDENCE_TEST_TENANT:-m5a-idem-test}" # ---- 参数:无参数时用默认目标;--log FILE 把输出同时落盘 ---- LOG="" ARGS=() while [ $# -gt 0 ]; do case "$1" in --log) LOG="${2:-}"; shift 2 ;; *) ARGS+=("$1"); shift ;; esac done [ ${#ARGS[@]} -gt 0 ] || ARGS=(${DEFAULT_TARGET}) if [ -n "${LOG}" ]; then mkdir -p "$(dirname "${LOG}")" set +e "${PY}" -m pytest "${ARGS[@]}" 2>&1 | tee "${LOG}" RC=${PIPESTATUS[0]} set -e echo "# RC=${RC}" >> "${LOG}" else "${PY}" -m pytest "${ARGS[@]}" RC=$? fi exit ${RC}