执行摘要
- 一句话:CI卫生:强制__main__入口,删除静默跳过测试,修复rerun-test
- 推荐动作:该PR值得精读,尤其关注
ci_register.py中AST验证的实现模式,这是一种轻量级且有效的CI防护手段。设计决策:使用静态分析而非运行时检查,避免了性能开销。同时,删除测试文件时保留原作者信息和恢复路径,体现了良好的工程实践。
功能与动机
CI runner通过python3 file.py -f调用测试文件,但pytest风格文件若缺少if __name__ == "__main__":块,则仅import后退出0,测试函数从未执行,CI却显示绿色。此问题容易在review中漏掉,导致测试覆盖率虚高。PR body明确指出了根因和影响。
实现拆解
- AST健全性检查:在
python/sglang/test/ci/ci_register.py中添加_is_main_block_with_call函数,使用AST解析每个注册文件,检查是否存在调用unittest.main()或pytest.main()的可执行__main__块。collect_tests增加sanity_check=True参数,在收集测试时验证所有非disabled文件,未通过则报错。
- 修复静默跳过文件:为6个文件添加
__main__块和必要的fixture修复(如test_streaming_session_unit.py中_FakeReq.finished_len = None),使其在CI中实际执行。同时从test_dump_comparator.py中删除依赖GPU的TestMainBasic子集。
- 删除不可修复的跳过文件:删除9个因缺少
__main__、依赖特定硬件或性能断言而长期静默跳过的测试文件,包括test_bnb.py、test_int4fp8_moe.py、test_zimage_turbo.py、python/sglang/jit_kernel/tests/test_dependency.py、test_repeat_interleave.py、test_glm47_moe_detector.py、test_model_hooks.py、test_mrope.py、test_patch_embed_perf.py。PR body标注了原始作者,欢迎后续修复后重新添加。
- 修复rerun-test CPU job:在
.github/workflows/rerun-test.yml中添加Install protoc和Install Rust toolchain步骤,与pr-test.yml保持一致,避免sglang-grpc编译时因缺少protoc而失败。
关键文件:
python/sglang/test/ci/ci_register.py(模块 测试注册;类别 test;类型 test-coverage;符号 _is_main_block_with_call, ut_parse_one_file): 核心变更:添加AST健全性检查函数_is_main_block_with_call,在collect_tests中验证每个注册文件的__main__块存在性,是修复静默跳过漏洞的关键。
test/registered/unit/mem_cache/test_streaming_session_unit.py(模块 流式会话测试;类别 test;类型 test-coverage;符号 test_streaming_release_kv_cache_defers_tail_free): 直接修复目标:添加__main__块并修复_FakeReq.finished_len = None(与实际Req默认值一致),使4个测试函数在CI中实际运行。同时删除已被#22897取代的defers_tail_free测试。
.github/workflows/rerun-test.yml(模块 CI工作流;类别 infra;类型 configuration): 修复CPU重跑任务:添加protoc和rustup安装步骤,与pr-test.yml保持一致,避免sglang-grpc编译失败。
关键符号:_is_main_block_with_call, ut_parse_one_file, test_streaming_release_kv_cache_defers_tail_free
关键源码片段
python/sglang/test/ci/ci_register.py
核心变更:添加AST健全性检查函数_is_main_block_with_call,在collect_tests中验证每个注册文件的__main__块存在性,是修复静默跳过漏洞的关键。
def _is_main_block_with_call(filepath: str) -> bool:
"""检查文件是否包含调用unittest.main()或pytest.main()的可执行__main__块。"""
with open(filepath) as f:
tree = ast.parse(f.read())
# 遍历顶层节点,寻找 if __name__ == "__main__": 块
for node in ast.walk(tree):
if isinstance(node, ast.If) and _is_name_main(node):
# 在 if 块内查找函数调用
for child in ast.walk(node):
if isinstance(child, ast.Call):
func_name = _get_func_name(child)
if func_name in {"unittest.main", "pytest.main"}:
return True
return False
# 在 collect_tests 中调用
if sanity_check and registry_files:
for filepath in registry_files:
if not _is_main_block_with_call(filepath):
raise RuntimeError(f"{filepath} 缺少可执行的__main__块,将导致CI静默跳过")
评论区精华
fxmarty-amd: "Why are the tests removed? Does it not mean that some part of sglang codebase still exist, but are simply untested?"
作者回复:这些测试文件从未在CI中实际运行,删除是临时措施,后续PR会恢复并正确注册。团队已知此风险,并计划跟进修复。
- 删除测试文件是否导致功能未经测试 (question): 作者确认这些测试从未在CI中实际运行,删除是临时措施,后续PR会恢复并正确注册。团队已知风险。
风险与影响
- 风险:测试覆盖缺失:删除的9个测试文件对应功能(如BNB量化、MRoPE、模型钩子等)暂时失去CI覆盖,直到后续PR恢复。但原始代码从未在CI中执行,因此实际无回归风险。CI工作流修复:
rerun-test.yml的protoc修复确保CPU重跑任务不再因编译失败而阻塞,但若依赖版本变化可能仍需调整。
- 影响:对CI系统:显著提升测试覆盖率真实性,消除静默跳过漏洞。未来所有注册测试文件必须包含可执行
__main__块,否则CI会报错。对开发者:需确保新增测试文件遵循该规范,review时注意检查。对用户:无直接影响。对团队:降低了测试维护成本,但需在后续PR中恢复已删除测试文件。
- 风险标记:测试覆盖暂时缺失, CI工作流修复
关联脉络
- PR #22897 streaming session: trim spec v2 overshoot in cache_finished_req: 该PR被删除的
defers_tail_free测试意图已被此PR supersede,因此删除是合理的。
参与讨论