mcpField
F
flaky-smoke-tests

flaky-smoke-tests

github.com/microsoft测试与质量194.4k51 次安装今天更新
代码仓库

关于 flaky-smoke-tests

flaky-smoke-tests 是用于调查 Azure DevOps Flaky Smoke Tests 流水线中 VS Code 测试间歇性失败的技能,面向 CI 维护者。它指导从任务日志和运行产物定位失败迭代、分析 UI 事件链,并针对相关平台安排验证。

主要功能

  1. 01定位失败的测试迭代
  2. 02下载并关联任务日志与产物
  3. 03分析输入、请求和界面渲染链
  4. 04查找引入问题的提交
  5. 05安排定向流水线验证

适用场景

  1. 01调查定时流水线中的冒烟测试失败
  2. 02区分请求未发送与结果未呈现
  3. 03验证修复是否消除间歇性故障

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/vscode --skill flaky-smoke-tests

安装后在 Claude Code 中输入/flaky-smoke-tests确认已加载。

详细介绍

诊断不稳定的冒烟测试

遇到 Azure DevOps Flaky Smoke Tests 流水线失败时,请使用此技能:

  • 组织:https://dev.azure.com/monacotools
  • 项目:Monaco
  • 定义 ID:700
  • 流水线 YAML:build/azure-pipelines/product-smoke-flaky.yml
  • 定时运行:每天在 main 上运行两次

该流水线会从源代码构建 VS Code,并针对 iterations 参数中的每一项运行一次完整的 Electron 冒烟测试套件。每个平台会在一个作业中按顺序运行各次迭代。例外情况是 Windows 单元测试和集成测试:二者分别拆分为两个并行作业:WindowsSmokeFlakyUnit_odd / WindowsSmokeFlakyIntegration_odd 运行奇数次迭代,WindowsSmokeFlakyUnit_even / WindowsSmokeFlakyIntegration_even 运行偶数次迭代。每个分片都有自己的构件(logs-windows-x64-<unit|integration>-<odd|even>-<attempt>)和独立的 Slack 统计行。

重要的流水线行为

  • 每次迭代都是一个独立的时间线任务,名称为 Smoke test iteration <N>/<total> (Electron)。
  • 迭代任务使用 continueOnError: true,因此失败的迭代通常结果为 succeededWithIssues,后续迭代仍会继续运行。
  • 不要根据整个构建或作业的结果来判断冒烟测试是否正常。检查每个迭代任务。
  • 每个平台作业只会从共享的 .build/logs 目录发布一次日志。构件的作用范围是作业,而不是迭代:smoke-test-runner.log 可能包含多次迭代的内容,套件目录也不会按迭代区分。
  • 调查期间,如果仍需要该平台作业的日志构件,请勿取消该作业。即使一个或多个失败迭代任务的日志已可用,取消也可能导致完全跳过发布步骤。如果验证运行已经确定会失败,可以让当前作业运行完成,或者排入一次诊断迭代,并让该作业完成发布后再继续调查。
  • 后续迭代可能会覆盖或截断共享日志目录中的文件。因此,最终构件可能包含最后一次迭代的套件目录或运行器日志,却不包含失败迭代的详细诊断信息。请保留精确的任务日志;如果需要失败尝试中的扩展宿主、渲染器、模拟服务器、屏幕截图或跟踪证据,请运行一次迭代的诊断运行。
  • 精确的迭代任务日志是其失败摘要和时间范围的权威来源。将该时间范围与作业级构件进行关联。
  • 迭代可能会读取之前迭代遗留的冒烟测试状态,例如历史会话行。切勿假定看起来最新的行或匹配的提示词属于当前对话,除非已确认当前视图。

平台定义和构件:

平台作业日志构件崩溃构件
macOS arm64macOSSmokeFlakylogs-macos-arm64-smoke-<attempt>crash-dump-macos-arm64-smoke-<attempt>
Windows x64WindowsSmokeFlakylogs-windows-x64-smoke-<attempt>crash-dump-windows-x64-smoke-<attempt>
Linux x64LinuxSmokeFlakylogs-linux-x64-smoke-<attempt>crash-dump-linux-x64-smoke-<attempt>

先决条件

使用 Azure CLI,而不是浏览器:

az --version
az extension show --name azure-devops
az devops configure --defaults \
  organization=https://dev.azure.com/monacotools \
  project=Monaco

如果身份验证失败,请运行 az login。

1. 确认构建和源代码修订版本

az pipelines build show \
  --id <BUILD_ID> \
  --org https://dev.azure.com/monacotools \
  --project Monaco \
  --query "{id:id,status:status,result:result,sourceBranch:sourceBranch,sourceVersion:sourceVersion,templateParameters:templateParameters}" \
  --output json

记录 sourceVersion。调查流水线实际构建的代码,而不是当前工作树。

2. 查找失败的迭代

下载构建时间线:

az devops invoke \
  --org https://dev.azure.com/monacotools \
  --area build \
  --resource timeline \
  --route-parameters project=Monaco buildId=<BUILD_ID> \
  --output json

筛选名称包含 Smoke test iteration 的任务记录。将结果为 succeededWithIssues、failed 或包含错误问题的任务视为失败迭代。记录:

  • 任务 id
  • 父作业 id
  • 任务 name
  • startTime 和 finishTime
  • log.id
  • issues

如果用户提供了 Azure 日志 URL,其中的 j= 值是作业 ID,t= 值是任务 ID。直接查询这些记录:

az devops invoke \
  --org https://dev.azure.com/monacotools \
  --area build \
  --resource timeline \
  --route-parameters project=Monaco buildId=<BUILD_ID> \
  --query "records[?id=='<JOB_OR_TASK_ID>'].{id:id,parentId:parentId,name:name,type:type,state:state,result:result,logId:log.id,startTime:startTime,finishTime:finishTime,issues:issues}" \
  --output json

3. 下载确切迭代任务日志

使用时间线记录中的 log.id。正确的 REST 资源是 logs,而不是 buildLog:

az devops invoke \
  --org https://dev.azure.com/monacotools \
  --area build \
  --resource logs \
  --route-parameters project=Monaco buildId=<BUILD_ID> logId=<LOG_ID> \
  --out-file task-log.json

下载的响应是 JSON,其中包含一个 value 数组,每行日志对应一个字符串。将其转换为纯文本。

PowerShell:

(Get-Content -Raw task-log.json | ConvertFrom-Json).value |
  Set-Content task-log.txt

Bash:

jq -r '.value[]' task-log.json > task-log.txt

即使平台产物尚未发布,任务日志也会提供简明的 Mocha 失败信息、堆栈和该迭代的确切时间范围。通过 smoke runner 的 Logger 写入的诊断信息(包括 dumpFailureDiagnostics)可能只存在于 smoke-test-runner.log 中,因此不要假设它们会出现在 Azure 任务日志中。

4. 下载平台日志产物

先列出产物;名称中包含作业尝试次数:

az pipelines runs artifact list \
  --run-id <BUILD_ID> \
  --org https://dev.azure.com/monacotools \
  --project Monaco \
  --output table

下载相关平台的产物:

az pipelines runs artifact download \
  --run-id <BUILD_ID> \
  --artifact-name <LOGS_ARTIFACT> \
  --path <DESTINATION> \
  --org https://dev.azure.com/monacotools \
  --project Monaco

平台作业发布其输出后,产物才可用。运行被取消后缺少平台产物是正常情况,并不表示产物名称有误。

5. 关联失败信息

从 <DESTINATION>/smoke-tests-electron/smoke-test-runner.log 开始。使用失败任务的时间戳和测试标题,找出匹配的 Test start / Test end 时间段。不要使用测试标题首次出现的位置,因为 runner 日志中可能包含多次迭代。

在该时间段内,确认以下链路:

  1. 手势:是否点击了预期的编辑器并输入了提示词?
  2. 分发:发送操作是否触发,新会话视图是否关闭?
  3. 请求:mock 服务是否收到了预期的场景标签?
  4. 工具循环:对于 shell 测试,第二次模型请求是否包含预期的工具结果?
  5. 渲染:助手响应是否已渲染?在哪个会话视图中?
  6. 路由:活动会话是否自动切换到新的编辑框,同时已完成的响应仍留在另一个会话中?

对于 mock-LLM 套件,请搜索:

  • 场景 ID
  • request body:
  • 预期的响应标记
  • model turn 1/2 和 model turn 2/2

请求日志可用于区分:

  • 未分发
  • 提供方或场景错误
  • 工具调用从未执行
  • 工具结果已返回,但 UI 渲染或路由未能呈现

然后检查套件目录:

smoke-tests-electron/<N>_suite_<Suite_Name>/

有用的文件包括:

  • window*/exthost/<extension>/<extension>.log
  • main.log、renderer.log 和 agenthost.log
  • copilot-runtime-logs/process-*.log — Copilot 运行时(@github/copilot CLI)进程日志;Copilot 运行时会话失败时,dumpFailureDiagnostics 会捕获这些日志。遇到**卡住或“等待响应超时”**时,先检查这些日志:它们是 SDK/CLI 自身的记录(启动、身份验证、模型请求、轮次生命周期、崩溃、乱序或协议错误),可以解释仅凭测试错误无法说明的超时。日志尾部也会镜像到 smoke-test-runner.log。Agent Host 会话(Agents Window / 本地 AgentHost)会以 trace 级别写入完整的日志运行记录;Chat Sessions 编辑器(Copilot CLI / Claude)和本地会话在此处只写入最简启动日志(说明运行时是否已启动),详细诊断信息则在 GitHub Copilot Chat.log 中。(Claude / Codex 会话使用不同的运行时,不会记录在此处。)
  • playwright-screenshot-*.png
  • Playwright 跟踪存档

对于原生退出或渲染器崩溃,还要下载平台崩溃产物。

6. 谨慎解读 UI 诊断信息

会话列表文本和当前视图文本回答的是不同问题:

  • 列表行可能包含当前测试中的提示词,但命令或标题可能继承自先前的请求。
  • 当前视图可能已经是一个全新的未命名编辑器,而响应属于一个已完成且未激活的会话。
  • 范围过广的响应选择器可能匹配到较早会话或迭代中的过期 DOM。
  • 重复使用固定的预热场景标记,可能导致后续预热等待匹配到较早的响应,从而放弃实际仍在运行的预热。
  • 通过 installAllHandlers 创建的标准冒烟测试套件会使用不同的随机用户数据目录。除非比较日志中实际的 vscode-userdata: 或 --user-data-dir 路径,否则不要将前一个套件中的设置归因于失败的套件。各次迭代会共享更广泛的作业状态,但同级套件通常不会共用同一配置文件。
  • 设置变更可能改变症状,而非修复问题。每次验证运行都要重新检查确切的堆栈,以及手势、调度、请求和渲染链路。例如,将扩展启用操作移到启动前,可能消除编辑器打开超时,但也会导致扩展在写入测试设置前就被激活,从而引发后续请求或响应超时。

优先使用能够确认身份的断言:

  • 每次尝试使用唯一的场景 ID 或响应标记
  • 当前聊天/会话的资源属性
  • 后续输入前,当前会话中已有预期响应
  • 手势触发后,模拟服务器的请求计数或捕获到的请求内容

不要只通过延长超时时间来“修复”这些竞态。应等待实际状态转换,或移除重复或正在进行中的工作。

7. 找出引入问题的提交

使用构建的 sourceVersion,并根据堆栈确定源文件:

git show <SOURCE_VERSION>:test/smoke/src/areas/<area>/<test>.test.ts
git log --oneline <KNOWN_GOOD>..<SOURCE_VERSION> -- <relevant paths>
git blame -L <start>,<end> <file>
git show <SUSPECT_COMMIT> -- <relevant paths>

追踪完整的因果过程,而不只是失败的断言。例如,检查设置钩子、预热、会话选择、响应等待和拆卸。

区分:

  • 引入竞态行为的提交
  • 后续无关的提交,而该提交之后的时序恰好暴露了问题
  • 仅添加诊断信息或使间歇性故障显现的提交

只有当差异中包含导致问题的行为,且流水线证据与之吻合时,才指出引入问题的提交。

8. 排队运行针对性验证

分支和提交必须已推送到 microsoft/vscode。排队前,检查并取消同一分支上过时的 definition-700 运行。

由于 iterations 是一个对象参数,请直接使用 az pipelines run:

az pipelines run \
  --id 700 \
  --branch <BRANCH> \
  --commit-id <COMMIT_SHA> \
  --parameters "iterations=[1,2,3,4,5,6]" \
    VSCODE_BUILD_MACOS=true \
    VSCODE_BUILD_LINUX=false \
    VSCODE_BUILD_WIN32=true \
  --org https://dev.azure.com/monacotools \
  --project Monaco \
  --output json

只启用与故障相关的平台。使用 az pipelines build show 确认已排队运行的 sourceVersion 和 templateParameters。

进行 6 次迭代是快速验证的实用样本。如果故障较少见,或要在宣布某个反复出现的间歇性故障已解决之前进行验证,请使用默认值 20。

9. 验证本地更改

对于冒烟测试中的 TypeScript 更改:

npm run compile --prefix test/smoke
node --experimental-strip-types build/hygiene.ts <changed-file>

如果本地依赖缺失或过时,请明确说明,并依靠针对性的 definition-700 运行进行完整的编译验证;不要悄悄跳过验证,也不要安装无关工具。

预期报告

总结:

  • 构建 ID 和源修订版本
  • 失败的平台和迭代次数
  • 失败测试的确切名称和症状
  • 调度、请求和渲染证据
  • 根本原因
  • 引入问题的提交,以及该提交导致问题的原因
  • 修复提交
  • 针对性验证运行 ID、平台、迭代次数和当前结果

评论

支持 Markdown