Files
Haocode/docs/agent-handoff/evidence/P2-04.md
T
2026-09-17 16:30:02 +08:00

8.3 KiB
Raw Blame History

P2-04 证据:跨平台聚合测试入口

状态:COMPLETE 日期:2026-07-17(本机执行时间) 平台:Windows 11 10.0.26200 x64(主)+ WSL Ubuntu-22.04 / CPython 3.12.3Linux 路径验证)

交付物

  • tests/run_all.py(新增,唯一新文件):跨平台聚合测试入口。
    • python tests/run_all.py --group logic|offscreen|all(默认 all
    • --list 只列条目;--only <id,子串> 跑子集(调试);--keep-logs 保留全部子日志(默认只留失败/超时)。
    • 设计:每个子测试 = 独立子进程 + 独立临时目录(haocode_RUN_<id>/haocode_CONF_<id>POSIX 走 TMPDIR、Windows 走 TEMP+ 显式秒级 timeoutsubprocess.run(timeout=...));offscreen 组子进程注入 QT_QPA_PLATFORM=offscreenHAOCODE_RENDER=softwareQTWEBENGINE_CHROMIUM_FLAGS=--disable-gpu(均 setdefault,不覆盖外层)。
    • 退出码语义:任一 FAIL/TIMEOUT → 退出码 1(并打印"失败命令"清单);SKIP 不影响退出码。
    • SKIP 双闸门:①依赖探测(importlib.util.find_specnode/openai/PyMuPDF/PyQt6,缺失即 SKIP 并给理由);②平台令牌(platform:win32 等,平台不适用即 SKIP 并给理由)。
    • 聚合鲁棒性:子进程崩溃/超时只记 FAIL/TIMEOUT,不中断后续;输出统一 UTF-8(errors=replaceWindows cp936/cp1252 宿主安全);WSL 时钟回拨保护(耗时 clamp ≥0)。
    • 不要求 pytest / npm / 网络;聚合器自身零第三方依赖。

默认聚合范围(25 条)与排除项

  • logic 12 条:run_tests.pyagent core 41)、test_tool_params、test_bash_stream、test_copy_session、test_compaction_persist、test_file_attach、test_cross_platform_shell、test_global_hotkey_platforms、test_wv2_guard、test_pdf_reader、test_math_extract.js、test_render_window.js。
  • offscreen 13 条:smoke_offscreen、smoke_mode、smoke_copy_session、smoke_bash_panel、smoke_timeline、smoke_midswitch、test_main_window_event_filter、test_config_isolation、test_error_persist、test_think_code_neutral、test_debug_window、test_renderer_matrix、test_screen_capture_platforms。
  • 默认排除(有注释理由,不进默认聚合):
    • diag_*rename_overlay / panel_scrollbar / render_scale):人工/像素诊断,需真机或交互。
    • verify_*:人工验证脚本。
    • tune_model_popup.py:调参实验。
    • smoke_offscreen.py 之外的旧式 real-DB 冒烟(引用真实 data/haocode.db,未接临时库)。
    • diag_live_agent.pyprobe_agent_loop.py:需真实 API 凭据。
    • _probe_*_test_env.py:探针/工具模块(被其他测试 import,非独立用例)。
    • run_all.py 自身:聚合器不入聚合。

汇总结果(硬约束要求:Windows/Linux 各一份)

Windows 11 / CPython 3.10.21.venvPyQt6+openai+PyMuPDF 齐全)

结果 耗时
--group logic PASS 12 / FAIL 0 / SKIP 0EXIT=0 43.9s
--group offscreen PASS 13 / FAIL 0 / SKIP 0EXIT=0 81.9s
--group all 25/25 PASSEXIT=0,两组顺序执行) ~126s
  • 日志样例:D:/tmp/runall_win_logic2.logD:/tmp/runall_win_offscreen.log
  • offscreen 明细:smoke_offscreen 8.3s、smoke_bash_panel 30.3s、smoke_midswitch 8.7s、test_think_code_neutral 9.3s 等 13 条全 PASS。

WSL Ubuntu-22.04 / CPython 3.12.3(系统 python3,无 PyQt6/openai/PyMuPDF,离线环境)

结果 耗时
--group all PASS 4 / FAIL 0 / SKIP 21EXIT=0 0.9s
  • PASS 4 = test_copy_session、test_file_attach、test_math_extract.js、test_render_window.js(纯 stdlib/node)。
  • SKIP 21 全部带明确理由:无 openai(5,禁止联网安装)、无 PyQt6(14offscreen 组整体)、无 PyMuPDF1)、平台不适用 win32-only1test_wv2_guardmsvcrt 单实例互斥是 WebView2 守卫的 Windows 专属机制,Linux 无 WebView2 链路)、无 PyQt6 的 GUI 逻辑(1test_global_hotkey_platforms 含 QShortcut 构造)。
  • 证明:聚合器在 Linux/3.12 上可运行、隔离约定在 POSIX(TMPDIR)成立、诚实 SKIP 不伪装通过、JS 条目跨平台运行。
  • 注:WSL 无 .venv 且离线,依赖型条目按硬约束 SKIP;在按 VERIFICATION 矩阵备齐依赖的 Linux 真机上同命令即可执行全部条目(offscreen 组仍需真实 Linux 桌面环境完成 P1-03/P1-04 的平台验证,状态不变)。

故意失败夹具演示(硬约束:崩溃/超时不阻断汇总、退出码反映失败)

  • 临时夹具(用后即删,未提交):
    • 崩溃夹具(raise RuntimeError)→ 聚合器记 FAIL 并继续跑后续健康测试。
    • 超时夹具(time.sleep(60) + budget 5s)→ 聚合器记 TIMEOUT 并继续。
  • 演示运行:总计 3: PASS 1 FAIL 1 TIMEOUT 1,退出码 1,完整汇总 + 失败命令清单正常打印。
  • 演示日志:D:/tmp/runall_fixture_demo.log;夹具文件已删除,仓库无残留(已 rg 复核)。

等价性(硬约束:单文件命令仍可直接运行,输出与聚合子进程一致)

  • test_copy_session.py
    • 独立运行:===== 54/54 PASS ===== / ALL PASS
    • 聚合子进程(保留子日志 tail):===== 54/54 PASS ===== / ALL PASS —— 逐字一致。
  • 其余条目同理(聚合即 subprocess.run([sys.executable, ...原命令...]),命令形态未变)。

聚合入口暴露并修复的两个真实缺陷

  1. tests/test_compaction_persist.py T9 陈旧断言(跨平台共同项,Windows 上 FAIL):
    • 断言用 assertIn('msg["role"] not in', src) 硬编码变量名,而 ui/views/main_window.py 现行代码用 m["role"] not inP1-01/P2-01 期间变量名演化,测试未跟进)。
    • 修复:改为变量名无关的语义断言(同时接受 msg["role"] not in / m["role"] not in 两种等价写法,检查"摘要标记行被过滤"这一语义本身)。
    • 验证:单跑 41/41 PASS;聚合 logic 组 12/12 PASS。
  2. core/agent/compaction.py dataclass 不可哈希默认值(Python 3.11+ 崩溃,真跨平台 bug
    • CompactionPreparation.settings: CompactionSettings = DEFAULT_COMPACTION_SETTINGS:默认值是 eq-dataclass 实例(__hash__=None)。Python ≤3.10 的 dataclass 只拒 list/dict/set 默认值 → 合法;Python 3.11+ 追加"不可哈希默认值"检查 → import 即 ValueError
    • 影响面:Ubuntu 24.04 自带 CPython 3.12VERIFICATION 矩阵明确支持的 Linux 目标)—— 任何 import core.agent 的模块/测试在 3.11+ 全灭。由聚合入口在 WSL/3.12 上首次系统性暴露。
    • 修复(1 行,语义完全等价):settings: CompactionSettings = field(default_factory=lambda: DEFAULT_COMPACTION_SETTINGS) —— 仍返回同一共享默认实例,3.10 行为不变。
    • 验证:3.10 本地 test_compaction_persist 41/41 + run_tests 41/41 无回归;WSL/3.12 上 core.agent 链 import 通过(3 个 openai 依赖条目越过 compaction 后才在 openai 处 SKIP,证明 3.12 兼容)。

注册表元数据修正(诚实 SKIP 的前提)

  • test_tool_params.py / test_bash_stream.py / test_cross_platform_shell.py:补 openai 依赖(均 import core.agent.tools → 顶层 from openai import OpenAI)。
  • test_global_hotkey_platforms.py:补 pyqt6 依赖(含 QShortcut/overlay 构造)。
  • test_wv2_guard.py:标 platform:win32T4 msvcrt 跨进程互斥为 Windows 专属;非 win32 上 acquire_instance_lock() 按设计返回 None)。

边界遵守

  • 未动任何独立测试命令与既有入口(run_tests.py 原样保留)。
  • 未要求 pytest/npm/网络;聚合器零第三方依赖。
  • 默认聚合未启动任何真实 API / 人工诊断 / 真实桌面 / 凭据脚本(见排除清单)。
  • 未读取真实配置(data/config.json 零访问);未删除用户运行数据;夹具用后即删。
  • 产品代码改动仅 2 处且均为聚合暴露的缺陷修复:tests/test_compaction_persist.py(测试断言更新)+ core/agent/compaction.py1 行 3.11+ 兼容)。

复现命令

python tests/run_all.py --list
python tests/run_all.py --group logic
python tests/run_all.py --group offscreen
python tests/run_all.py --group all
python tests/run_all.py --only test_copy_session --keep-logs