执行摘要
- 一句话:为CI添加pytest失败日志收集与持久化功能,提升调试效率。
- 推荐动作:该PR值得快速浏览,重点关注
pytest_runtest_makereport钩子的实现方式,以及文件名清洗和导入结构调整的设计决策。对于CI基础设施维护者,可借鉴其日志收集机制以优化其他项目的测试调试流程。
功能与动机
根据PR body描述,动机是“增强CI调试能力,通过收集详细的pytest失败日志,减少不稳定或失败用例的排查时间”。这旨在解决CI环境中测试失败时调试困难的问题,提升开发和维护效率。
实现拆解
- 新增pytest钩子实现日志收集:在
tests/conftest.py中新增pytest_runtest_makereport钩子,捕获测试失败时的错误信息,并写入FD_LOG_DIR目录下的日志文件,文件名基于测试用例名生成。
- 调整conftest.py导入和结构:将
e2e.utils.serving_utils导入移至文件顶部,并添加日志目录创建逻辑到pytest_configure中,同时重构代码注释以提升可读性。
- 禁用不稳定测试文件:将
tests/e2e/4cards_cases/test_Qwen3_30b_tp4.py重命名为_test_Qwen3_30b_tp4.py,以禁用该不稳定测试。
- 更新CI脚本排除干扰:修改
scripts/coverage_run.sh,在grep命令中添加--exclude="pytest_*_error.log"选项,避免日志收集产生的错误日志干扰CI输出。
关键文件:
tests/conftest.py(模块 测试框架;类别 test;类型 test-coverage;符号 pytest_configure, pytest_collection_modifyitems, pytest_runtest_makereport, FDRunner): 核心变更文件,新增pytest钩子实现日志收集,并调整导入和配置逻辑。
tests/e2e/4cards_cases/_test_Qwen3_30b_tp4.py(模块 端到端测试;类别 test;类型 rename-or-move): 通过重命名禁用不稳定的测试文件,避免CI失败干扰。
scripts/coverage_run.sh(模块 脚本工具;类别 infra;类型 configuration): 更新CI脚本以排除pytest错误日志,避免干扰CI输出。
关键符号:pytest_runtest_makereport, pytest_configure, pytest_collection_modifyitems
关键源码片段
tests/conftest.py
核心变更文件,新增pytest钩子实现日志收集,并调整导入和配置逻辑。
import os
import re
import pytest
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""
捕获失败测试用例并将错误日志保存到FD_LOG_DIR。
仅记录测试执行阶段的失败,不包含setup/teardown阶段。
"""
outcome = yield
report = outcome.get_result()
if report.when == "call" and report.failed:
# 从item.nodeid提取测试用例名,并清洗非法字符以确保文件名安全
raw_name = item.nodeid.split("::", 1)[-1]
case_name = re.sub(r'[\\/:*?"<>|]', '_', raw_name) # 替换特殊字符为下划线
log_dir = os.environ.get("FD_LOG_DIR", "log")
log_file = os.path.join(log_dir, f"pytest_{case_name}_error.log")
# 将错误信息写入日志文件
with open(log_file, "w", encoding="utf-8") as f:
f.write(f"Test failed: {item.nodeid}\n")
if call.excinfo is not None:
f.write(f"Exception: {call.excinfo}\n")
if report.longrepr is not None:
f.write(f"Traceback: {report.longrepr}\n")
评论区精华
- 文件名安全性问题:PaddlePaddle-bot指出
case_name未做安全清洗,参数化测试中含/等字符可能导致日志写入失败,建议添加清理逻辑。作者在后续提交中通过正则表达式修复了此问题。
- 导入风险疑问:PaddlePaddle-bot询问将
e2e.utils.serving_utils提升为顶层导入是否会导致非e2e测试的collection失败,但未得到明确回复,此疑虑未解决。
- 脚本选项位置建议:PaddlePaddle-bot建议将
--exclude选项放在位置参数前以避免POSIX兼容性问题,但PR中未采纳此建议。
- 临时测试修改:Review中发现了多个测试文件中的断言被反转为
!=,这是用于验证日志收集功能的临时修改,作者在后续提交中移除了这些调试代码。
- 文件名安全性清洗 (correctness): 作者在后续提交中添加了正则表达式清洗逻辑,替换非法字符为下划线。
- 顶层导入风险 (design): 未得到明确回复,疑虑未解决,可能依赖环境配置。
- 脚本选项位置 (style): PR中未采纳此建议,选项仍放在位置参数后。
风险与影响
- 风险:1. 导入依赖风险:
conftest.py中顶层导入e2e.utils.serving_utils,若该模块在非e2e测试环境中不可用,可能导致所有测试的collection阶段失败。
2. 日志文件路径安全:尽管已添加文件名清洗,但case_name清洗逻辑可能未覆盖所有边缘情况,如过长文件名或特殊编码字符,仍可能引发文件操作异常。
3. CI脚本兼容性:coverage_run.sh中--exclude选项放在位置参数后,在严格POSIX环境下可能失效,导致错误日志未被排除,干扰CI输出。
4. 测试覆盖影响:禁用test_Qwen3_30b_tp4.py可能降低对该模型特定配置的测试覆盖,需确保其他测试能补偿。
- 影响:1. 对用户影响:无直接影响,主要面向开发者和CI维护者,提升测试失败时的调试效率。
2. 对系统影响:新增日志文件可能增加磁盘使用量,但通过环境变量FD_LOG_DIR可控制目录,影响有限。
3. 对团队影响:简化CI故障排查流程,减少手动日志收集时间,提升开发迭代速度。
- 风险标记:导入依赖风险, 文件路径安全, 脚本兼容性
关联脉络
- PR #7429 [CI] Add approval check for logging-related modifications: 同属CI和日志相关改进,涉及脚本和审批流程优化。
- PR #7190 [Feature] implement log channel separation and request log level system: 涉及日志系统增强,本PR的日志收集机制可视为其补充。
参与讨论