[インデックス 14862] ファイルの概要
コミット
このコミットは、Go言語のテストインフラストラクチャにおける変更であり、特にtest/dwarf
ディレクトリ下のテストがrun.go
によって適切にサポートされるようにするためのものです。具体的には、テストの実行ディレクトリ(rundir
)がコンパイルディレクトリ(compiledir
)およびエラーチェックディレクトリ(errorcheckdir
)と一致するように調整されています。これにより、Goのデバッグ情報フォーマットであるDwarfに関連するテストが、Goの標準テストランナーであるrun.go
で実行可能になります。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c3836ed06ea30f5c9a5aacd90e3c48164065971c
元コミット内容
test: make rundir match compiledir/errorcheckdir.
This allows test/dwarf to be supported by run.go.
Update #4139.
R=golang-dev, bradfitz, iant
CC=golang-dev
https://golang.org/cl/7064067
変更の背景
Go言語のテストスイートは、様々な種類のテストを効率的に実行するためにrun.go
という汎用的なテストランナーを使用しています。しかし、特定のテスト、特にDwarfデバッグ情報に関連するテスト(test/dwarf
ディレクトリ下)は、そのディレクトリ構造や実行時の要件が他のテストと異なっていたため、run.go
による自動実行が困難でした。
このコミットの背景には、run.go
がテストを実行する際に、テストファイルのコンパイルが行われるディレクトリ(compiledir
)と、テスト実行時に期待される出力やエラーがチェックされるディレクトリ(errorcheckdir
)の概念が存在します。test/dwarf
のテストは、これらのディレクトリの概念と実行時のカレントディレクトリ(rundir
)との整合性が取れていなかったため、run.go
が正しくテストを認識・実行できない問題がありました。
この変更は、test/dwarf
テストをrun.go
のフレームワークに統合し、テストの自動化とメンテナンス性を向上させることを目的としています。また、コミットメッセージにある「Update #4139」は、この問題に関連する内部トラッキングまたは以前の議論を示唆しています。
前提知識の解説
- Go言語のテストフレームワーク: Go言語には、
go test
コマンドを通じて実行される組み込みのテストフレームワークがあります。大規模なプロジェクトでは、go test
のラッパーとして、より複雑なテストシナリオや環境設定を扱うためのカスタムテストランナーが使用されることがあります。Goの標準ライブラリのテストでは、test/run.go
がその役割を担っています。 run.go
: Goプロジェクトのテストディレクトリ(test/
)にあるカスタムテストランナーです。これは、Goのテストスイート全体を管理し、様々な種類のテスト(コンパイルテスト、実行テスト、エラーチェックテストなど)を実行するためのロジックを含んでいます。run.go
は、テスト対象のソースコードを一時ディレクトリにコピーし、そこでコンパイル・実行を行うことで、テスト環境の分離とクリーンアップを容易にします。- Dwarf (Debugging With Arbitrary Record Formats): Unix系システムで広く使われているデバッグ情報フォーマットです。コンパイラやリンカが生成する実行ファイルに埋め込まれ、デバッガがソースコードレベルでのデバッグ(変数名の解決、ブレークポイントの設定、スタックトレースの表示など)を行うために必要な情報を提供します。Go言語のコンパイラもDwarf形式のデバッグ情報を生成します。
rundir
,compiledir
,errorcheckdir
:run.go
のようなテストランナーが内部的に使用する概念です。compiledir
: テスト対象のソースコードがコンパイルされる一時ディレクトリ。errorcheckdir
: テストの出力やエラーメッセージが期待されるパターンと照合されるディレクトリ。rundir
: テストが実際に実行されるカレントディレクトリ。 これらのディレクトリが一致しない場合、特にファイルパスの解決や相対パスの参照において問題が発生する可能性があります。
skipOkay
マップ:test/run.go
内で使用されるマップで、特定のテストファイルがスキップされても問題ない(つまり、テストが失敗しても全体の結果に影響しない)ことを示すために使われます。これは、特定の環境でのみ失敗するテストや、まだ完全に統合されていないテストに対して一時的に使用されることがあります。
技術的詳細
このコミットの主要な技術的変更点は、test/dwarf
ディレクトリの構造変更と、test/run.go
におけるテスト実行ロジックの修正です。
-
test/dwarf
ディレクトリの再編成:test/dwarf/main.go
やtest/dwarf/z1.go
といった既存のテストファイルが、test/dwarf/dwarf.dir/main.go
、test/dwarf/dwarf.dir/z1.go
のように、dwarf.dir
という新しいサブディレクトリに移動(リネーム)されています。- 同時に、
test/dwarf/dwarf.go
という新しいファイルが作成されています。このファイルは、// rundir
というコメントを含んでおり、このディレクトリがテストの実行ディレクトリとして機能することを示唆しています。このファイル自体はpackage ignored
となっており、直接実行されるコードではなく、ディレクトリ構造のマーカーやメタデータとして機能していると考えられます。 この再編成により、test/dwarf
のテストは、run.go
が期待するcompiledir
/errorcheckdir
/rundir
の統一された構造に適合するようになります。
-
test/run.go
の変更:goDirPackages
の利用: 以前はgoDirFiles
を使ってディレクトリ内の個々のGoファイルを処理していましたが、変更後はgoDirPackages
を使ってパッケージ単位で処理するようになっています。これにより、Goのパッケージ構造をより適切に扱えるようになり、複数のファイルで構成されるパッケージのコンパイルが容易になります。- コンパイルとリンクのロジックの変更:
run.go
のtest.run()
メソッド内のcase "run"
セクションで、テストのコンパイルと実行ロジックが修正されています。- 以前は、ディレクトリ内のすべてのGoファイルを個別にコンパイルし、最後にディレクトリ内の最後のファイルをメインパッケージとしてリンクしていました。
- 変更後は、
goDirPackages
が返すパッケージのリストを反復処理し、各パッケージをcompileInDir
でコンパイルします。そして、pkgs
の最後の要素(つまり最後のパッケージ)に対してのみlinkFile
を実行し、その結果生成された実行ファイル(a.exe
)を実行するように変更されています。これにより、test/dwarf
のような複数のGoファイルで構成されるテストが、単一の実行可能ファイルとして正しくビルド・実行されるようになります。
skipOkay
マップからのdwarf
関連エントリの削除:test/run.go
のskipOkay
マップから、dwarf/main.go
やdwarf/z*.go
といったdwarf
関連のファイルパスが大量に削除されています。これは、上記の変更によってtest/dwarf
のテストがrun.go
で正常に実行可能になったため、もはやスキップする必要がなくなったことを意味します。
これらの変更により、test/dwarf
のテストはrun.go
のテスト実行フローに完全に統合され、GoのCI/CDパイプラインで自動的に実行・検証されるようになります。
コアとなるコードの変更箇所
test/dwarf/dwarf.go
(新規追加)
// rundir
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// See issue 2241 and issue 1878: dwarf include stack size
// issues in linker.
package ignored
test/run.go
--- a/test/run.go
+++ b/test/run.go
@@ -292,7 +292,7 @@ func goDirPackages(longdir string) ([][]string, error) {
}
return pkgs, nil
}
-
+
// run runs a test.
func (t *test) run() {
defer close(t.donec)
@@ -459,31 +459,32 @@ func (t *test) run() {
// Compile all files in the directory in lexicographic order.
// then link as if the last file is the main package and run it
longdir := filepath.Join(cwd, t.goDirName())
- files, err := goDirFiles(longdir)
+ pkgs, err := goDirPackages(longdir)
if err != nil {
t.err = err
return
}
- var gofile os.FileInfo
- for _, gofile = range files {
- _, err := compileInDir(runcmd, longdir, gofile.Name())
+ for i, gofiles := range pkgs {
+ _, err := compileInDir(runcmd, longdir, gofiles...)
if err != nil {
t.err = err
return
}
- }
- err = linkFile(runcmd, gofile.Name())
- if err != nil {
- t.err = err
- return
- }
- out, err := runcmd(append([]string{filepath.Join(t.tempDir, "a.exe")}, args...)...)
- if err != nil {
- t.err = err
- return
- }
- if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
- t.err = fmt.Errorf("incorrect output\n%s", out)
+ if i == len(pkgs)-1 {
+ err = linkFile(runcmd, gofiles[0])
+ if err != nil {
+ t.err = err
+ return
+ }
+ out, err := runcmd(append([]string{filepath.Join(t.tempDir, "a.exe")}, args...)...)
+ if err != nil {
+ t.err = err
+ return
+ }
+ if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
+ t.err = fmt.Errorf("incorrect output\n%s", out)
+ }
+ }
}
case "build":
@@ -603,7 +604,7 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
out[i] = strings.Replace(out[i], full, short, -1)
}
}
-
+
var want []wantedError
for j := 0; j < len(fullshort); j += 2 {
full, short := fullshort[j], fullshort[j+1]
@@ -726,27 +727,6 @@ var skipOkay = map[string]bool{
"rotate.go": true,
"sigchld.go": true,
"sinit.go": true,
- "dwarf/main.go": true,
- "dwarf/z1.go": true,
- "dwarf/z10.go": true,
- "dwarf/z11.go": true,
- "dwarf/z12.go": true,
- "dwarf/z13.go": true,
- "dwarf/z14.go": true,
- "dwarf/z15.go": true,
- "dwarf/z16.go": true,
- "dwarf/z17.go": true,
- "dwarf/z18.go": true,
- "dwarf/z19.go": true,
- "dwarf/z2.go": true,
- "dwarf/z20.go": true,
- "dwarf/z3.go": true,
- "dwarf/z4.go": true,
- "dwarf/z5.go": true,
- "dwarf/z6.go": true,
- "dwarf/z7.go": true,
- "dwarf/z8.go": true,
- "dwarf/z9.go": true,
"fixedbugs/bug248.go": true, // combines errorcheckdir and rundir in the same dir.
"fixedbugs/bug302.go": true, // tests both .$O and .a imports.
"fixedbugs/bug313.go": true, // errorcheckdir with failures in the middle.
コアとなるコードの解説
test/dwarf/dwarf.go
このファイルは、test/dwarf
ディレクトリがrun.go
によってテスト実行ディレクトリ(rundir
)として認識されるためのマーカーとして機能します。// rundir
というコメントは、このディレクトリの役割を明確に示しています。package ignored
であることから、このファイル自体がコンパイルされて実行されることはなく、主にディレクトリ構造のセマンティクスを定義するために存在します。また、Dwarfのリンカに関する既存の課題(issue 2241とissue 1878)への言及は、このテストスイートが特定のデバッグ情報関連の問題を検証するために設計されていることを示唆しています。
test/run.go
の変更点
-
goDirFiles
からgoDirPackages
への変更:- 変更前は
files, err := goDirFiles(longdir)
を使用してディレクトリ内の個々のGoファイルを取得していました。 - 変更後は
pkgs, err := goDirPackages(longdir)
を使用しています。goDirPackages
は、ディレクトリ内のGoファイルをパッケージ単位でグループ化して返します。これにより、Goのモジュールシステムやパッケージの概念に沿ったテストのコンパイル・実行が可能になります。test/dwarf
のテストが複数のGoファイルで構成される場合、これらを単一のパッケージとして扱うことで、コンパイルとリンクが正しく行われるようになります。
- 変更前は
-
コンパイルと実行ロジックの改善:
- 以前のループでは、ディレクトリ内のすべてのGoファイルを個別に
compileInDir
でコンパイルし、ループの最後にgofile
変数に格納された最後のファイル名を使ってlinkFile
を実行していました。これは、単一のGoファイルで構成されるテストには適していましたが、複数のファイルで構成されるパッケージには不十分でした。 - 新しいロジックでは、
for i, gofiles := range pkgs
というループが導入されています。gofiles
は、特定のパッケージに属するGoファイルのリストです。- 各パッケージ内のファイルは
compileInDir(runcmd, longdir, gofiles...)
によってコンパイルされます。gofiles...
は、スライスを展開して可変長引数として渡すGoの機能です。 - 最も重要な変更は、
if i == len(pkgs)-1
という条件です。これは、pkgs
リストの最後のパッケージに到達した場合にのみ、linkFile
とテストの実行を行うことを意味します。これにより、複数のパッケージが存在する場合でも、テストスイート全体として単一の実行可能ファイルが生成され、それが実行されるという意図が明確になります。 - 実行結果の検証(
strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput()
)は、以前と同様に行われます。
- 各パッケージ内のファイルは
- 以前のループでは、ディレクトリ内のすべてのGoファイルを個別に
-
skipOkay
マップからのエントリ削除:skipOkay
マップからdwarf/
以下の多数のファイルパスが削除されたことは、これらのテストがもはやスキップされることなく、run.go
によって正常に実行されるようになったことを明確に示しています。これは、test/dwarf
テストの統合が成功したことの証です。
これらの変更は、Goのテストインフラストラクチャの堅牢性を高め、Dwarfデバッグ情報に関連する重要なテストが自動化されたテストスイートの一部として確実に実行されるようにするために不可欠です。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Go言語のテストに関するドキュメント: https://go.dev/doc/code#Testing
- Dwarfデバッグ情報フォーマットに関する情報 (一般的な情報源): https://dwarfstd.org/
参考にした情報源リンク
- Go言語のGitHubリポジトリ: https://github.com/golang/go
- Go言語のコードレビューシステム (Gerrit): https://go.dev/cl/ (コミットメッセージに記載されている
https://golang.org/cl/7064067
はこのシステムへのリンクです) - Go言語のIssueトラッカー (以前のIssue 4139に関する直接的な公開情報は見つかりませんでしたが、GoのIssueは通常GitHubまたはGoのGerritシステムで管理されます。)
- Go GitHub Issues: https://github.com/golang/go/issues
- Dwarfデバッグ情報に関する一般的な技術記事や仕様書。
- Go言語のテストフレームワークの内部実装に関する分析記事やドキュメント。