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

testing: add goroutine labels to tests

ステータス変更: likely_accept accepted

要約

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

概要

テスト・ベンチマーク・Fuzzテスト実行時に、それぞれのgoroutineへ自動的に「どのテストか」を示すラベル(test.nameとtest.iter)を付与する提案です。タイムアウトやパニック時のトレースバック、pprofプロファイルからテストの特定を容易にします。

ステータス変更

likely_accept → accepted
2026-09-16のレビューで「likely accept」となった後、9/23のレビューでも合意内容に変更がなかったため、9/24に正式にacceptedとなりました。ラベルのキー名(test.name/test.iter)や、両者を1つのラベルに統合すべきか(neild氏の"test: TestWithPanic#0"案)といった論点も議論されましたが、最終的にはpprofでの-count反復の集約・フィルタリングのしやすさを優先し、2つの独立したラベルとする案(提案者の当初案に近い形)で合意に至りました。この issue は今後、実装作業の追跡issueとして使われます。

技術的背景

現状の問題点

多数のテストが並行実行される状況でタイムアウトが発生した場合、runtimeが出力する「まだ実行中のゴルーチン一覧」だけでは、各goroutineがどのテスト関数に対応するのか分かりません。例えば以下のようなトレースバックがあっても、どのテストがハングしているのか特定するのは困難でした。

goroutine 36 gp=0x33789cd803c0 m=0 mp=0x6d37e0 [running]:
panic({0x690ff8?, 0x550230?})
        /path/to/runtime/panic.go:879 +0x16f

提案された解決策

testingパッケージが、各テスト/ベンチマーク/Fuzzテストの実行開始時にruntime/pprofのgoroutineラベル機構(pprof.Do相当、internal/runtime/pprof.SetGoroutineLabels経由)を使い、以下の2つのラベルを自動付与します。

  • test.name: テスト関数名(Test、Example、Benchmark、Fuzzの接頭辞を含む、パッケージ名は含まない)
  • test.iter: -test.countによる反復を識別する値(0始まりのインデックス)。Fuzzテストでは追加情報を含む場合があります。
    これはコンテキスト経由ではなく、goroutineローカルなラベルとして設定されるため、panic時のトレースバックのgoroutineステータス行や、-cpuprofile/-test.cpuprofileによるpprofプロファイル(goroutineラベルを保持するprotobuf形式)にも反映されます。なお、ラベルをトレースバックに表示する機能自体は関連issue #23458(go.dev/cl/694119、Go 1.26でGODEBUG=tracebacklabels=1により先行実装済み)で扱われており、本提案はそのラベル付けの発生源となるtestingパッケージ側の変更です。

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

複数goroutineが絡むテストの障害調査が大幅に容易になります。

  • タイムアウト・デッドロック調査: -test.timeout超過時に出力される大量のgoroutineダンプの中から、どれがどのテストに属するgoroutineかを一目で判別できます。
  • パニック発生時のトレースバック解析: recoverされたパニックのスタックトレースにテスト名・反復回数が表示され、-countの何回目の実行で問題が起きたかが分かります。
  • CPUプロファイルの分析: -cpuprofileで取得したプロファイルにテストラベルが付与されるため、pprofの-tagfocus/-taghide等でテスト単位に絞り込んだ分析が可能になります。

コード例

// Before: パニック時のトレースバックにはテスト名の手がかりがない
goroutine 36 gp=0x33789cd803c0 m=0 mp=0x6d37e0 [running]:
panic({0x690ff8?, 0x550230?})
        /path/to/runtime/panic.go:879 +0x16f
// After: ゴルーチンにtest.name / test.iterラベルが自動付与される
goroutine 36 gp=0x33789cd803c0 m=0 mp=0x6d37e0 [running] {test.iter: 2, test.name: TestWithPanic}:
panic({0x690ff8?, 0x550230?})
        /path/to/runtime/panic.go:879 +0x16f

開発者側はt.Runなどの既存APIをそのまま使うだけで、追加コードなしにこの恩恵を受けられます。

議論のハイライト

  • 反復ラベルの扱い: 当初案では-countの2回目以降のみにtest.iterを付与する想定でしたが、レビューで「1回目だけラベルがないのは不自然」との指摘があり、常に付与する方針に変更されました。
  • ラベルを1本化するか2本に分けるか: neild氏がtest: Name#iterのような単一ラベル案を提案しましたが、提案者は「pprofで-count反復を無視して集約したい場面がある」ことを理由に反対し、最終的にtest.nameとtest.iterの2ラベル構成で合意しました。
  • ベンチマークの反復番号の定義: b.Loopを使わない旧来の自動スケーリングのベンチマークでは、セットアップコードが複数回実行されるため「反復番号」の意味が曖昧になりますが、レビューでは深追いせず、単純に-count由来の最外周のインデックスを使う方針となりました。
  • パッケージ名を含めるか: test.nameにパッケージ名を含めるかも議論されましたが、Goのテストバイナリは1パッケージのみを扱うため不要と判断されました。
  • 既存のラベル機構との整合性: prattmic氏の確認により、これらのラベルはruntime/pprof.Do相当の標準的なセマンティクスに従い、SetGoroutineLabelsでクリアされない限り子goroutineにも継承されることが明確化されました。
  • 表示順序に関する軽微な指摘: レビュー後、prattmic氏から「test.iterがtest.nameより先に表示されるのは分かりにくいのでは」との指摘があり、実装時の細部として今後検討される見込みです。

関連リンク