如何识别 Ansible 的附带代码覆盖缺口?下载 AZP 覆盖数据并运行 incidental.py
【免费下载链接】ansibleAnsible is a radically simple IT automation platform that makes your applications and systems easier to deploy and maintain. Automate everything from code deployment to network configuration to cloud management, in a language that approaches plain English, using SSH, with no agents to install on remote systems. https://docs.ansible.com.项目地址: https://gitcode.com/GitHub_Trending/ans/ansible
在 Ansible 仓库里做测试相关的二次开发时,经常会遇到一个问题:某些代码之所以有覆盖,只是因为别的测试“顺手”跑到了它们。这种现象叫附带测试和附带代码覆盖(incidental testing and code coverage)——例如dnf集成测试本意是测dnf模块,过程中却无意覆盖并测试了file模块。在模块和插件迁移进 collections 时,仓库保留了这类只提供独占覆盖的集成测试,并统一加上incidental_前缀(例如 test/integration/targets/incidental_win_reboot),其长期目标是逐步用有意的测试替换它们。
要判断哪些代码目前只靠附带测试在覆盖,Ansible 提供了 hacking/azp/ 目录下的三个脚本,完整流程记录在 hacking/azp/README.md 中:
- get_recent_coverage_runs.py:获取最近带代码覆盖的 CI 测试运行(Azure Pipelines)的 URL 与状态;
- download.py:从 Azure Pipelines 下载指定运行的覆盖数据到本地;
- incidental.py:基于下载的数据在本地分析,生成附带覆盖报告。
前提条件:
- 本地有一份 Ansible 源码的 git 仓库,并且包含目标覆盖运行对应的 commit(
incidental.py会用git show校验该 commit 是否存在); - 能访问 Azure Pipelines 的 API,因为覆盖数据全部来自 CI;
- 运行
incidental.py时需要ansible-test在$PATH中,文档要求的做法是source hacking/env-setup(见 hacking/env-setup)。
第一步:找到可用的覆盖测试运行
整套测试带代码覆盖的完整运行每天在 Azure Pipelines 上自动执行一次。先用下面命令查询最近的这类运行:
hacking/azp/get_recent_coverage_runs.py <可选的分支名>分支名默认为devel。输出按结束时间排列,每条记录带有结果标记(PASS或FAIL)、对应的运行页面链接和结束时间,例如:
🙂 [PASS] https://dev.azure.com/ansible/ansible/_build/results?buildId=<runId> (2026-09-08T02:00:00)(以上为文档描述的输出格式,<runId>与时间为实际运行时给出的值。)
从PASS的记录里选一条运行,记下它的 run id(buildId)。incidental.py只接受成功的运行:如果下载的数据对应失败的运行,脚本会直接报错并要求“re-run until passing, then download the latest results and re-run the report using those results”。
第二步:下载覆盖数据到本地
拿到 run id 后,用download.py下载该运行的产物:
# 将 14075 替换为第一步中选定的运行编号 hacking/azp/download.py 14075 --artifacts --run-metadata -v参数说明(均取自脚本自身的--help):
- 位置参数
RUN:AZP 运行编号,也可以直接传该运行的 Azure Pipelines URI; --artifacts:下载 artifacts(覆盖数据在其中);--run-metadata:下载运行元数据,写入run.json,incidental.py从中读取运行对应的 commit 和结果状态;-v:打印实际下载了什么。
注意该命令的副作用:它会在当前工作目录下创建一个以运行编号命名的目录(例如14075/),把 artifacts 解压进去并写入run.json。因此建议在 Ansible 仓库根目录下执行,后续第三步正是以这个目录作为输入。如果想先预览而不下载,可加-t(--test)参数,脚本只会显示将要下载的内容。
第三步:运行 incidental.py 生成报告
确保ansible-test在$PATH中,然后指向刚下载的目录运行:
source hacking/env-setup # 使用第二步实际下载到的目录,例如 14075/ hacking/azp/incidental.py 14075/脚本执行时依次完成:校验本地仓库中存在该运行的 commit;确认运行结果为succeeded;确认下载目录里存在*/coverage-analyze-targets.json覆盖数据;然后调用ansible-test coverage analyze targets的combine、filter、missing、expand子命令合并并对比覆盖数据。
成功后,标准输出会为每个被分析的 target 打印一行摘要:
<target 名称>: <arcs 数> arcs, <lines 数> lines, <files 数> files - <报告相对路径>报告文件默认写入test/results/.tmp/incidental/{hash}/reports/目录,{hash}由本次使用的输入文件计算得到;也可以用--output指定其他输出目录。脚本默认分析匹配^incidental_的集成测试 target,可用--targets传入其他正则。
如果报告只反映默认口径,注意脚本还会在 stderr 提示:该报告只展示对这些 target独占的覆盖——随着这些 target 被移除,剩余 target 的独占覆盖会增加。
如何阅读报告
报告包含每一行被覆盖的代码:左列是源码行号,右侧(对 Python 代码)以注释标出涉及的覆盖弧(arc)。下面是文档给出的示例(文档示例,行号与数值以你实际运行结果为准):
Target: incidental_win_psexec GitHub: <该 target 源码在仓库中的链接,含匹配覆盖率数据的 commit> Source: lib/ansible/executor/task_executor.py (2 arcs, 3/1141 lines): GitHub: <该源文件在仓库中的链接,含匹配的 commit> 705 if 'rc' in result and result['rc'] not in [0, "0"]: ### (here) -> 706 706 result['failed'] = True ### 705 -> (here) ### (here) -> 711 711 if self._task.until: ### 706 -> (here)(示例中的GitHub:行是报告自动生成的源码链接,这里仅作说明性占位。)
读法要点,均见 hacking/azp/README.md:
- 报告指明负责覆盖的测试 target,并给出与覆盖率数据 commit 匹配的源码链接;
### (here) -> 706(在 705 行)表示执行流从 705 行流向 706 行,可以有多个流出行号;### 706 -> (here)(在 711 行)表示从 706 行流向 711 行,可以有多个流入行号;(here)即当前源码行;- 弧(arcs)只对 Python 代码提供;PowerShell 代码只报告覆盖的行号;
- 报告不会说明这些附带覆盖具体来自哪个测试,只能告诉你缺口在哪。
可选:按插件路径查找覆盖缺口
附带覆盖不限于incidental_前缀的测试:某个 filter 插件自身测试的覆盖缺口,也可能被无关测试补上了。incidental.py可以用--plugin-path {path_to_plugin}参数对指定插件出一份“缺少哪些覆盖”的报告(该参数与--targets互斥)。对多个插件重复此步即可;文档给出的批量示例是对所有filter插件各出一份报告:
# 将 14075/ 替换为你实际下载的结果目录 find lib/ansible/plugins/filter -name '*.py' -not -name __init__.py -exec hacking/azp/incidental.py 14075/ --plugin-path '{}' ';'每份报告会列出该插件自身测试中缺失的附带代码覆盖。
常见错误与限制
- commit not found:本地仓库缺少运行对应的 commit,报错会提示 “make sure your source repository is up-to-date”,先把仓库更新到包含该 commit 再重跑;
- 结果不是 succeeded:脚本中止并要求先让 CI 重跑至通过,再下载最新结果重新分析;可用
--skip-checks跳过完整性检查,但文档明确说该参数“use only for debugging”; - no coverage data found:下载目录里没有覆盖数据,通常是下载的并非一次代码覆盖运行(或漏了
--artifacts); - 下载选项:
download.py至少需要--artifacts、--run-metadata、--console-logs(或--all)之一,否则会报错退出。
删除附带测试时还有一条文档明确的注意事项:一次只应移除一个incidental_测试,否则可能使另一个测试获得独占的附带覆盖。
下一步
报告定位到缺口之后,按 hacking/azp/README.md 给出的流程,第 4 步是:为新发现的缺口创建有意的测试,或扩展现有测试去覆盖这些代码。随着有意测试不断加入,附带测试提供的独占覆盖会持续下降,当某个附带测试不再提供独占覆盖时,就可以将其移除而不损失测试覆盖。
【免费下载链接】ansibleAnsible is a radically simple IT automation platform that makes your applications and systems easier to deploy and maintain. Automate everything from code deployment to network configuration to cloud management, in a language that approaches plain English, using SSH, with no agents to install on remote systems. https://docs.ansible.com.项目地址: https://gitcode.com/GitHub_Trending/ans/ansible
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考