Prhub

#2279 Run the launch script snapshot tests by hand instead of in CI

原始 PR 作者 fzyzcjy 合并时间 2026-08-09 18:59 文件变更 6 提交数 19 评论 0 代码增减 +13 / -3

执行摘要

启动脚本快照测试移出 CI,改为手动执行

PR body 说明:CI runner 通过 tests/ci/ci_register.py 中的 _DISCOVERY_ROOTS 发现 tests/fast、tests/fast-gpu、tests/e2e、tests/ci 下的测试,且 tests/fast 下一切按位置隐式注册。这 4 个快照测试只在改动 launcher 或 model 定义时有验证价值(例如把 62 个 shell 版 model 配置改写成 python 时需要快照锚定行为),每次 CI 都跑收益低、成本高;把它们移到 tests/manual 可以“不删除但退出 CI 默认发现范围”,既保留回归网又避免每次 CI 重复付出约 495 个用例的成本。

值得快速阅读,重点理解“用目录位置控制 CI 发现范围”的模式与 tests/snapshots/README.md 中固化下来的手动执行约定;若团队后续想把更多重测试移出 CI,tests/manual 目录可复用。本 PR 无源码逻辑改动,不建议作为精读对象,但建议在未来修改 tests/ci/ci_register.py 或移动 harness 时回头核对本 PR 建立的路径耦合。

讨论亮点

本 PR 没有任何 review 评论(comments_count 与 review_comments_count 均为 0),无评审交锋可提炼。设计取舍体现在 PR body 与提交信息中:作者强调“移出发现范围而非禁用”,用目录位置替代 skip 标记,保证测试随时可手动运行;提交历史中反复出现 Keep the generated snapshots under one obvious tests/snapshots tree、Group the launch script tests by subject 等工程化约束,说明该快照体系是逐步收敛的结果,而非一次性设计。

实现拆解

  1. 迁移测试文件:4 个快照测试文件(test_model_args.py、test_py_launch_scripts.py、test_sh_launch_scripts.py、test_self_executing_launchers.py)整体 rename 到 tests/manual/launch_scripts/,内容零改动(+0/-0,纯文件移动),并新增 tests/manual/launch_scripts/init.py 使其成为可导入的测试包。
  2. 保留 harness 与 CI 覆盖:sh_harness.py、py_harness.py、model_args_harness.py 留在 tests/fast/launch_scripts,因此 harness 自测(test_sh_harness.py)与 shell 脚本卫生检查(test_shell_script_hygiene.py)继续在 CI 中运行;迁移后的测试继续按绝对路径 tests.fast.launch_scripts.* 导入这些 harness,测试内容无需任何改动。
  3. 更新快照文档:tests/snapshots/README.md 把各目录的生成方路径从 tests/fast/launch_scripts/test_.py 改为 tests/manual/launch_scripts/test_.py,补齐原来缺失的 launch_scripts/self_executing/ 与 model_args/ 两行说明,并新增手动运行命令(pytest tests/manual/launch_scripts)与重新生成快照命令(MILES_UPDATE_LAUNCH_SCRIPT_SNAPSHOTS=1 pytest tests/manual/launch_scripts)。
  4. 验证:discover_ci_files() 在 launch_scripts 下现在只返回 test_sh_harness.py 与 test_shell_script_hygiene.py;本地执行 pytest tests/manual/launch_scripts 495 passed、pytest tests/fast/launch_scripts 39 passed、pytest tests/ci 319 passed 1 skipped。
文件 模块 状态 重要度
tests/manual/launch_scripts/test_model_args.py 模型参数 renamed 3.53
tests/manual/launch_scripts/test_py_launch_scripts.py 启动脚本 renamed 3.18
tests/manual/launch_scripts/test_sh_launch_scripts.py 启动脚本 renamed 3.18
tests/manual/launch_scripts/test_self_executing_launchers.py 启动脚本 renamed 3.18
tests/manual/launch_scripts/__init__.py 测试包 added 3.18
tests/snapshots/README.md 快照文档 modified 2.82

关键符号

test_model_args_match_snapshot test_model_args_are_flags_and_values test_every_model_is_discovered_and_snapshotted recorded (fixture in test_sh_launch_scripts.py) recorded (fixture in test_self_executing_launchers.py) _glm_checkpoint / _nemotron_checkpoint (test_py_launch_scripts.py)

关键源码片段

tests/manual/launch_scripts/test_model_args.py rename-or-move

覆盖 60+ 模型 golden argv 的核心快照测试,是 4 个迁移对象中覆盖面最广的一个;内容零改动,迁移后仅手动运行。

import jsonimport pytest# 迁移后仍按绝对路径导入原位置 harness,保证 CI 中的 harness 自测与被迁移测试共用同一份实现
from tests.fast.launch_scripts.model_args_harness import expand_model_args, iter_model_types
from tests.fast.launch_scripts.sh_harness import REPO_ROOT, assert_matches_snapshot# 快照目录与模型枚举在模块加载时确定,手动执行与 CI 执行行为一致
_SNAPSHOT_DIR = REPO_ROOT / "tests" / "snapshots" / "model_args"_MODEL_TYPES = iter_model_types()
​
​
class TestEveryModelType:
    @pytest.mark.parametrize("model_type", _MODEL_TYPES)
    def test_model_args_match_snapshot(self, model_type: str) -> None:
        """每个模型的 golden argv,防止后续重写模型定义时悄悄漂移"""
        # 逐 token 做 json.dumps 后按行拼接,使快照可读且可精确比对
        actual = "\n".join(json.dumps(token) for token in expand_model_args(model_type)) + "\n"
​
        assert_matches_snapshot(_SNAPSHOT_DIR / f"{model_type}.txt", actual, model_type)
​
    @pytest.mark.parametrize("model_type", _MODEL_TYPES)
    def test_model_args_are_flags_and_values(self, model_type: str) -> None:
        """消费端按空白切分 argv,含空白 token 会静默变成两个参数"""
        tokens = expand_model_args(model_type)
​
        assert tokens
        assert tokens[0].startswith("--")
        assert all(token == token.strip() and " " not in token for token in tokens)
​
​
class TestDiscovery:
    def test_every_model_is_discovered_and_snapshotted(self) -> None:
        """模型若不再匹配发现 glob,其 golden 文件会静默丢失,此测试兜底"""
        snapshotted = {path.stem for path in _SNAPSHOT_DIR.glob("*.txt")}
​
        assert set(_MODEL_TYPES) == snapshotted
        assert len(_MODEL_TYPES) > 60

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  1. CI 覆盖缩减(主要风险):约 495 个快照用例不再自动运行,launcher 或 model 定义回归只能靠手动执行 pytest tests/manual/launch_scripts 发现;若开发者改动后忘记补跑,回归可能直接合入 main。
  2. 绝对路径耦合:迁移后的测试仍 import tests.fast.launch_scripts.* 的 harness(如 sh_harness、py_harness、model_args_harness),未来 harness 一旦移动即破坏这些导入;_SNAPSHOT_DIR 也依赖 tests/snapshots 的相对目录布局。
  3. 文档与发现机制耦合:README 直接引用 _DISCOVERY_ROOTS 常量与 tests/ci/ci_register.py,若 CI 注册机制重构(改名或改为显式注册),该文档会失真。
  4. 无安全、性能或兼容性风险:纯测试文件搬移,运行时代码零改动。

对用户与系统无功能影响,运行时产物不变。对团队与 CI 的影响是双向的:每次 PR CI 减少约 495 个参数化快照用例,缓解 runner 压力,与近期多个 CI 减负 PR 方向一致;但代价是要求团队建立“改动 launcher 或 model 定义后手动补跑快照”的执行纪律,否则快照回归网形同虚设。影响范围仅限测试目录布局与 CI 测试发现结果。

CI 覆盖缩减 依赖人工执行纪律 绝对路径耦合 文档与发现机制耦合

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论