[インデックス 18227] ファイルの概要
このコミットは、Go言語の標準ライブラリos
パッケージ内のテストTestReaddirStatFailures
に関する変更です。具体的には、このテストがPlan 9オペレーティングシステム上で実行されないように修正されています。
コミット
commit 6f97ef28af33fb8c9a2ce19ae74f04cfbead7e7c
Author: David du Colombier <0intro@gmail.com>
Date: Mon Jan 13 13:24:59 2014 +0100
os: disable TestReaddirStatFailures on Plan 9
R=rsc, dave, aram, jeremyjackins, lucio.dere
CC=golang-codereviews, jas
https://golang.org/cl/50980043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6f97ef28af33fb8c9a2ce19ae74f04cfbead7e7c
元コミット内容
os: disable TestReaddirStatFailures on Plan 9
R=rsc, dave, aram, jeremyjackins, lucio.dere
CC=golang-codereviews, jas
https://golang.org/cl/50980043
変更の背景
TestReaddirStatFailures
は、os.Readdir
関数がディレクトリ内のエントリを読み取る際に、一部のエントリに対してLstat
(シンボリックリンクを解決しないstat
システムコール)が失敗した場合の挙動をテストするためのものです。
元のコードでは、Windows環境ではこのテストをスキップしていました。その理由は、Windowsのファイルシステム関連のシステムコールがUnix系OSとは異なり、Lstat
を使用するような構造になっていないため、テストの意図するシナリオ(Lstat
の失敗をシミュレートすること)が機能しないためでした。
このコミットの背景には、Plan 9環境においても同様の問題が存在することが判明したことがあります。Plan 9もまた、そのファイルシステムとシステムコールの設計が他のUnix系OSとは異なり、TestReaddirStatFailures
が期待通りに動作しない、あるいはテストの前提が成り立たない状況であったと考えられます。テストが特定の環境で常に失敗するか、またはテストの目的がその環境のシステムコール構造に合致しない場合、その環境でのテストをスキップすることは一般的なプラクティスです。これにより、CI/CDパイプラインのノイズを減らし、テスト結果の信頼性を向上させることができます。
前提知識の解説
os
パッケージ: Go言語の標準ライブラリの一部で、オペレーティングシステムとのインタラクション(ファイルシステム操作、プロセス管理など)を提供します。os.Readdir
: 指定されたディレクトリ内のすべてのファイルとディレクトリの情報を読み取り、os.FileInfo
インターフェースのスライスとして返します。os.FileInfo
: ファイルのメタデータ(名前、サイズ、パーミッション、最終更新時刻など)を表すインターフェースです。Lstat
システムコール: ファイルの情報を取得するシステムコールの一つです。stat
と異なり、シンボリックリンクを解決せずに、そのシンボリックリンク自体の情報を返します。TestReaddirStatFailures
では、このLstat
が意図的に失敗するシナリオをテストしています。runtime.GOOS
: Goプログラムが実行されているオペレーティングシステムを示す文字列定数です。例えば、"linux"
,"windows"
,"darwin"
(macOS),"plan9"
などがあります。- Plan 9: ベル研究所で開発された分散オペレーティングシステムです。Unixの概念をさらに推し進め、すべてのリソースをファイルとして扱うという思想が特徴です。ファイルシステムやシステムコールの設計がUnix系OSとは異なる点が多く、Go言語の移植においてもその違いが考慮されることがあります。
- テストのスキップ: Goのテストフレームワークでは、
t.Skip()
やt.Skipf()
を使って、特定の条件(例: 特定のOS、特定の環境変数)が満たされない場合にテストの実行をスキップすることができます。これにより、テストが不必要に失敗するのを防ぎ、テストスイート全体の信頼性を保ちます。
技術的詳細
TestReaddirStatFailures
は、os.Readdir
がディレクトリを読み取る際に、内部的に呼び出されるLstat
が失敗した場合の挙動を検証するテストです。このテストは、Readdir
が部分的な成功(一部のエントリは読み取れるが、一部のエントリのLstat
は失敗する)を適切に処理し、エラーを返すことを確認することを目的としています。
テストのメカニズムは、通常、Lstat
の動作をフック(差し替え)して、特定の条件下でエラーを返すようにシミュレートすることで実現されます。しかし、WindowsやPlan 9のようなOSでは、Readdir
の実装がLstat
を直接使用しない、あるいはLstat
の失敗をシミュレートするフックが機能しないような異なるシステムコール構造を持っている場合があります。
具体的には、Windowsの場合、Readdir
はFindFirstFile
/FindNextFile
のようなAPIを使用し、これらのAPIはファイル情報を一度に取得するため、個々のエントリに対するLstat
のような追加の呼び出しは行われません。同様に、Plan 9のファイルシステムインターフェースも、Unixのreaddir
とlstat
の組み合わせとは異なるセマンティクスを持つ可能性があります。
このため、これらの環境でTestReaddirStatFailures
を実行しても、テストの意図するシナリオが再現されず、テストが常に失敗するか、あるいはテストの目的が達成されないことになります。このコミットは、このような環境依存の挙動を考慮し、テストの実行をスキップすることで、テストスイートの安定性を向上させています。
コアとなるコードの変更箇所
変更はsrc/pkg/os/os_test.go
ファイル内のTestReaddirStatFailures
関数にあります。
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -396,11 +396,12 @@ func touch(t *testing.T, name string) {
}
func TestReaddirStatFailures(t *testing.T) {
- if runtime.GOOS == "windows" {
- // Windows already does this correctly, but is
- // structured with different syscalls such that it
- // doesn't use Lstat, so the hook below for testing it
- // wouldn't work.
+ switch runtime.GOOS {
+ case "windows", "plan9":
+ // Windows and Plan 9 already do this correctly,
+ // but are structured with different syscalls such
+ // that they don't use Lstat, so the hook below for
+ // testing it wouldn't work.
t.Skipf("skipping test on %v", runtime.GOOS)
}
dir, err := ioutil.TempDir("", "")
コアとなるコードの解説
変更前は、if runtime.GOOS == "windows"
という条件文でWindows環境でのみテストをスキップしていました。
変更後は、switch runtime.GOOS
文が導入され、"windows"
に加えて"plan9"
もスキップ対象に追加されました。これにより、WindowsとPlan 9の両方の環境でTestReaddirStatFailures
が実行される前にt.Skipf
が呼び出され、テストがスキップされるようになります。
コメントも更新され、「Windows and Plan 9 already do this correctly, but are structured with different syscalls such that they don't use Lstat, so the hook below for testing it wouldn't work.」と記述されています。これは、これらのOSがReaddir
の失敗ケースを適切に処理するものの、その内部実装がLstat
を使用しないため、テストが意図するLstat
の失敗をシミュレートするフックが機能しないことを明確にしています。
この変更は、Goのクロスプラットフォーム対応における細かな調整の一例であり、特定のOSのシステムコール特性に合わせてテストの挙動を調整することの重要性を示しています。
関連リンク
- Go言語の
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語の
runtime
パッケージドキュメント: https://pkg.go.dev/runtime - Go言語のテストに関するドキュメント: https://go.dev/doc/code#testing
- Plan 9 from Bell Labs: https://9p.io/plan9/
参考にした情報源リンク
- Go言語のソースコード (特に
src/pkg/os/
) - Go言語の公式ドキュメント
- Plan 9のシステムコールに関する一般的な情報 (Web検索)
stat
とlstat
システムコールの違いに関する情報 (Web検索)- WindowsのファイルI/O APIに関する情報 (Web検索)
- Go言語のコミット履歴とコードレビュー (GitHub, Go Gerrit)