flaky-smoke-tests について
flaky-smoke-tests は、Azure DevOps の Flaky Smoke Tests パイプラインで発生する VS Code テストの断続的な失敗を調べる手順です。CI の保守担当者向けに、失敗した反復の特定、ログや成果物による UI のイベント追跡、対象プラットフォームでの変更検証を説明します。
主な機能
- 01失敗したテスト反復の特定
- 02タスクログと成果物の取得・照合
- 03入力、リクエスト、UI 描画の追跡
- 04問題を導入したコミットの特定
- 05対象を絞ったパイプライン検証の実行
活用シーン
- 01定期パイプラインのスモークテスト失敗の調査
- 02リクエスト未送信と UI 未表示の切り分け
- 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で毎日 2 回
このパイプラインはソースから VS Code をビルドし、iterations パラメーターの各エントリに対して、Electron スモークテストスイート全体を 1 回実行します。各プラットフォームでは、1 つのジョブ内で各イテレーションを順番に実行します。例外は Windows のユニットテストと統合テストで、それぞれ 2 つの並列ジョブに分割されます。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ディレクトリからプラットフォームのジョブごとに 1 回だけ公開されます。アーティファクトのスコープはジョブ単位であり、イテレーション単位ではありません。smoke-test-runner.logには複数のイテレーションが含まれる場合があり、スイートのディレクトリもイテレーションごとに分けられていません。 - 調査中にログアーティファクトがまだ必要な場合は、プラットフォームのジョブをキャンセルしないでください。失敗したイテレーションタスクのログが 1 つ以上すでに利用可能でも、キャンセルによって公開ステップが完全にスキップされることがあります。検証実行の失敗が確実になった場合は、現在のジョブが完了するまで待つか、診断用のイテレーションを 1 回だけキューに入れ、そのジョブでアーティファクトを公開させてから反復調査してください。
- 後続のイテレーションによって、共有ログディレクトリ内のファイルが上書きまたは切り詰められることがあります。そのため、最終的なアーティファクトには最後のイテレーションのスイートディレクトリやランナーログが含まれていても、失敗したイテレーションの詳細な診断情報は含まれていない場合があります。タスクの正確なログを保存し、失敗した試行の拡張機能ホスト、レンダラー、モックサーバー、スクリーンショット、またはトレースの証拠が必要な場合は、1 イテレーションの診断実行を使用してください。
- 正確なイテレーションタスクのログを、失敗の概要と時間範囲を判断するための信頼できる情報源として扱ってください。その時間範囲をジョブレベルのアーティファクトと照合してください。
- イテレーションでは、過去のセッション行など、以前のイテレーションから保持されたスモークテストの状態が参照されることがあります。最も新しく見える行や、プロンプトが一致する行がアクティブな会話に属していると決めつけず、アクティブなビューを確認してください。
プラットフォームの定義とアーティファクト:
| プラットフォーム | ジョブ | ログアーティファクト | クラッシュアーティファクト |
|---|---|---|---|
| macOS arm64 | macOSSmokeFlaky | logs-macos-arm64-smoke-<attempt> | crash-dump-macos-arm64-smoke-<attempt> |
| Windows x64 | WindowsSmokeFlaky | logs-windows-x64-smoke-<attempt> | crash-dump-windows-x64-smoke-<attempt> |
| Linux x64 | LinuxSmokeFlaky | logs-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とfinishTimelog.idissues
ユーザーから 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 リソースは buildLog ではなく logs です。
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
ダウンロードしたレスポンスは、ログ行ごとに 1 つの文字列を格納した value 配列を含む JSON です。プレーンテキストに変換します。
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 の失敗内容、スタック、およびイテレーションの正確な時間範囲が記録されており、プラットフォームのアーティファクトが公開される前でも確認できます。スモークランナーの 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 の区間を特定します。テストタイトルが最初に出現した箇所は使わないでください。ランナーログには同じタイトルのイテレーションが複数含まれる場合があります。
その区間で、次の連鎖を確認します。
- ジェスチャー:想定されたエディターがクリックされ、プロンプトが入力されましたか?
- ディスパッチ:送信アクションが実行され、新規セッションのビューが閉じましたか?
- リクエスト:モックサーバーは想定されたシナリオタグを受信しましたか?
- ツールループ:シェルテストの場合、2 回目のモデルリクエストに想定されたツール結果が含まれていましたか?
- レンダリング:アシスタントの応答はレンダリングされましたか?また、どのセッションビューに表示されましたか?
- ルーティング:完了した応答が別のセッションに残ったまま、アクティブなセッションは新しい入力欄に自動的に切り替わりましたか?
モック LLM を使ったテストスイートでは、次を検索します。
- シナリオ ID
request body:- 想定された応答マーカー
model turn 1/2およびmodel turn 2/2
リクエストログから、次のいずれかを判別できます。
- ディスパッチされていない
- プロバイダーまたはシナリオが間違っている
- ツール呼び出しが実行されていない
- ツール結果は返されたが、UI でのレンダリングまたはルーティングで失われた
次に、スイートのディレクトリを調べます。
smoke-tests-electron/<N>_suite_<Suite_Name>/
確認に役立つファイルは次のとおりです。
window*/exthost/<extension>/<extension>.logmain.log、renderer.log、およびagenthost.logcopilot-runtime-logs/process-*.log— Copilot ランタイム(@github/copilotCLI)のプロセスログです。Copilot ランタイムのセッションが失敗した場合に、dumpFailureDiagnosticsによって取得されます。**ハングまたは「Timed out waiting for response」**が発生した場合は、まずここを確認してください。これらは 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、プラットフォーム、反復回数、現在の結果