メインコンテンツへスキップ
#75047likely_accept

testing: add goroutine labels to tests

ステータス変更: active likely_accept

要約

AIによる要約であり、誤りを含む場合があります。

概要

Goのtestingパッケージが、テスト・ベンチマーク・Fuzzテストの実行時に自動的にgoroutineラベルを付与できるようにする提案です。これにより、複数のテストが並行実行されている状況でも、どのgoroutineがどのテストに紐づくかを容易に識別できるようになります。

ステータス変更

active → likely_accept
2026年8月20日にactiveへ追加され、2回のproposal review会議(9/9、9/16)を経て、9/16に「likely accept」と判断されました。コアチームは基本方針には早期から賛同しており、議論の焦点はラベルのキー設計(何個、どんな名前にするか)に絞られていました。最終的に提案者(@dfinkel)の原案よりもシンプルな「test.nameとtest.iterの2種類のみ」という設計に収束し、合意に至ったことが承認の決め手となりました。

技術的背景

現状の問題点

テストがタイムアウトした際、go testは「まだ実行中のテスト一覧」を表示する機能を持っていますが、それとgoroutineのトレースバック(パニック時のスタックダンプなど)を突き合わせて「どのgoroutineがどのテストのものか」を特定する手段がありませんでした。特に大量のgoroutineをリークさせているテストを特定したり、CPUプロファイル(-cpuprofile)内でテストごとにサンプルを分類したりする際に不便でした。

提案された解決策

testingパッケージが各テスト/ベンチマーク/Fuzzテストの実行時に、runtime/pprofのgoroutineラベル機構(pprof.Doと同等のセマンティクス)を用いて以下の2つのラベルを自動付与します。

  • test.name: テスト関数名(Test/Example/Benchmark/Fuzzなどの接頭辞を含む、パッケージ名は含まない、サブテストの場合はt.Run()によるスラッシュ区切り名も含む)
  • test.iter: そのテスト関数の呼び出しを一意に識別する値。通常のテスト/ベンチマークでは-countによる0始まりの反復回数、Fuzzテストの場合はコーパスのシード/テストデータ名や実行時の引数情報なども含みうる(数値とは限らない)
    議論の過程で、提案者の当初案(test.iterは2回目以降の反復のみに付与、ベンチマーク用にbench.name/bench.run.iter、Fuzz用にfuzz.name/fuzz.corpus.name/fuzz.corpus.iterなど計7種類のラベルキーを用意)から、レビューを経て「初回反復にも一貫してtest.iterを付与する」「テスト・ベンチマーク・Fuzzすべてに共通するtest.name/test.iterの2つに集約する」というシンプルな設計に変更されました。これらのラベルは、これまで別issue(#23458)で議論されていたトレースバックへのgoroutineラベル出力機能(Go 1.26でGODEBUG=tracebacklabels=1により実験的に導入済み)と組み合わせて活用されることが想定されています。

これによって何ができるようになるか

テストのタイムアウトやデッドロック、パニックのデバッグ時に、トレースバック中のgoroutineヘッダーを見るだけで、そのgoroutineがどのテスト・どの反復に属するかが一目で分かるようになります。また、-cpuprofileで取得したCPUプロファイルはpprofのprotobuf形式でgoroutineラベルを保持するため、プロファイルをテストごとにフィルタ・集計する用途にも活用できます。
主なユースケース:

  1. 多数のサブテストを並行実行するテストスイートで、タイムアウト時にどのサブテストがハングしているかを特定する
  2. パニックのリカバリ後のトレースバックから、どのテストの何回目の実行(-count指定時)でパニックが発生したかを判別する
  3. CPUプロファイルをtest.nameでフィルタ・集計し、特定のテストが消費しているCPU時間を分析する

コード例

// Before: パニック時のトレースバックにテスト名の手がかりがない
goroutine 7 gp=0x1a2fc3f21860 m=0 mp=0x6d27e0 [running]:
panic({0x68ffb8?, 0x54f230?})
        /path/to/runtime/panic.go:879 +0x16f
testing.tRunner.func1.2(...)
// After: goroutineヘッダーにtest.name/test.iterラベルが自動付与される
goroutine 7 gp=0x1a2fc3f21860 m=0 mp=0x6d27e0 [running] {test.iter: 0, test.name: TestWithPanic}:
panic({0x68ffb8?, 0x54f230?})
        /path/to/runtime/panic.go:879 +0x16f
testing.tRunner.func1.2(...)
// -count=2 で2回目の実行の場合
goroutine 36 gp=0x33789cd803c0 m=0 mp=0x6d37e0 [running] {test.iter: 1, test.name: TestWithPanic}:

議論のハイライト

  • ラベル数の削減: 提案者は当初テスト種別ごとに異なるラベルキー(bench.name、fuzz.nameなど計7種類)を提案していましたが、@aclementsらとの議論で「テスト名には既にTest/Benchmark/Fuzzの接頭辞が含まれるため区別不要」との指摘があり、共通のtest.name/test.iterの2つに統合されました。
  • 反復番号の扱い: 当初案では初回実行時にはtest.iterを付けない設計でしたが、「1回目だけラベルがないのは不自然」との意見により、常に付与する方針に変更されました。
  • 単一ラベル案の検討と却下: @neildから「test.nameとtest.iterを1つのラベル(例: test: TestFoo#0)に統合してはどうか」との提案がありましたが、プロファイルでの反復番号の有無によるフィルタリング(-taghideで反復を無視して集計する用途など)がしにくくなるため、2ラベル案が維持されました。
  • ベンチマークの反復定義: b.Nベースの自動スケーリングループでは内部的に何度もセットアップコードが走るため「反復回数」の定義が曖昧になる問題が指摘されましたが、実用上は-count由来の最外周の反復番号のみを使えば十分と判断されました。
  • 既存のruntime/pprofセマンティクスとの整合性: @prattmicから「これらのラベルはpprof.Doと同じセマンティクス(SetGoroutineLabelsでクリアされない限り継承される)か」との確認があり、その通りであることが提案者から確認されました。

関連リンク