Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 16249] ファイルの概要

コミット

commit b461c94cfaf79f2f84abd7513eb35218dc6235ed
Author: Rob Pike <r@golang.org>
Date:   Tue Apr 30 13:17:37 2013 -0700

    os/exec: disable TestExtraFilesFDShuffle
    It's too hard to make portable just now.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/9057043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/b461c94cfaf79f2f84abd7513eb35218dc6235ed

元コミット内容

os/exec: disable TestExtraFilesFDShuffle
It's too hard to make portable just now.

変更の背景

このコミットは、Go言語の標準ライブラリos/execパッケージ内のTestExtraFilesFDShuffleというテストを無効化するものです。コミットメッセージには「It's too hard to make portable just now.」(現時点ではポータブルにするのが難しすぎる)と明記されており、このテストが様々なオペレーティングシステム(OS)環境で一貫して動作するように実装することが困難であるという判断が下されたことが背景にあります。

os/execパッケージは、外部コマンドを実行するための機能を提供します。このパッケージでは、子プロセスにファイルディスクリプタ(File Descriptor, FD)を渡すためのExtraFilesという機能があります。TestExtraFilesFDShuffleは、このExtraFiles機能が正しく動作し、特にファイルディスクリプタの順序が子プロセス内で正しく「シャッフル」(またはマッピング)されることを検証するためのテストでした。しかし、ファイルディスクリプタの扱いはOSによって挙動が異なる場合があり、特にテスト環境におけるその挙動の再現性や予測可能性を確保することが難しいと判断されたため、一時的にテストをスキップする措置が取られました。

前提知識の解説

ファイルディスクリプタ (File Descriptor, FD)

ファイルディスクリプタは、Unix系OSにおいて、プロセスが開いているファイルやソケット、パイプなどのI/Oリソースを識別するために使用される整数値です。プロセスがファイルを開くと、OSはそのファイルに対応するファイルディスクリプタをプロセスに割り当てます。標準入力(stdin)、標準出力(stdout)、標準エラー出力(stderr)はそれぞれ0、1、2という固定のファイルディスクリプタが割り当てられています。

os/execパッケージ

Go言語のos/execパッケージは、外部コマンドを実行し、その入出力を制御するための機能を提供します。Cmd構造体を通じて、実行するコマンド、引数、環境変数、作業ディレクトリなどを設定できます。

Cmd.ExtraFiles

Cmd構造体にはExtraFilesというフィールドがあります。これは、子プロセスに継承させたい追加のファイルディスクリプタのリストを指定するために使用されます。例えば、親プロセスで開いたファイルを子プロセスでも利用したい場合などに使われます。子プロセスでは、これらのファイルディスクリプタは指定された順序で、標準のファイルディスクリプタ(0, 1, 2)の次に続く番号(通常は3から始まる)として利用可能になります。

syscall.StartProcess

os/execパッケージの内部では、OS固有のシステムコールを呼び出すためにsyscallパッケージが利用されます。特に、子プロセスを起動する際にはsyscall.StartProcessのような関数が使われます。この関数は、ProcAttr構造体を引数に取り、その中のFilesフィールドを通じて、子プロセスに渡すファイルディスクリプタのリストを指定します。os/execパッケージのExtraFilesは、このsyscall.StartProcessFilesフィールドにマッピングされます。

ポータビリティ (Portability)

ポータビリティとは、ソフトウェアが異なる環境(OS、ハードウェアアーキテクチャなど)でも修正なし、または最小限の修正で動作する能力を指します。ファイルディスクリプタの扱いはOSによって微妙に異なる場合があり、特にテストの文脈では、特定のOSの挙動に依存するテストは他のOSで失敗する可能性があります。これが「ポータブルにするのが難しい」という問題の根源です。

技術的詳細

TestExtraFilesFDShuffleは、os/execパッケージが子プロセスにExtraFilesを通じてファイルディスクリプタを渡す際の挙動を検証するものでした。具体的には、syscall.StartProcessProcAttr.Filesに渡されたファイルディスクリプタを、子プロセス内で連続したファイルディスクリプタ(0, 1, 2の次に続く番号)としてマッピングする挙動をテストしていました。

このテストが「ポータブルにするのが難しい」とされた理由はいくつか考えられます。

  1. OS間のファイルディスクリプタ管理の違い:

    • Unix系OSではファイルディスクリプタは整数ですが、その割り当てや内部的な管理方法はOSカーネルの実装によって異なります。
    • 特に、子プロセスにファイルディスクリプタを渡す際の「シャッフル」や「マッピング」の挙動が、OSのバージョンや種類(Linux、macOS、FreeBSDなど)によって微妙に異なる可能性があります。
    • 例えば、特定のOSではファイルディスクリプタのクローズや再利用のタイミングが異なり、テストが意図しないファイルディスクリプタを拾ってしまう可能性も考えられます。
  2. テスト環境の非決定性:

    • テストが実行される環境(CI/CDパイプライン、開発者のローカルマシンなど)によって、利用可能なファイルディスクリプタの番号や状態が異なることがあります。
    • 並行して実行される他のテストやプロセスがファイルディスクリプタを消費・解放することで、テストの前提が崩れる可能性があります。
    • 特に、ファイルディスクリプタの「シャッフル」を検証するようなテストは、OSがファイルディスクリプタをどのように割り当てるかという非決定的な要素に依存しやすいため、安定したテストを書くのが困難になります。
  3. GoランタイムとOSの相互作用:

    • Goランタイム自体が内部的にファイルディスクリプタを管理しており、それがos/execパッケージを通じてOSのシステムコールとどのように相互作用するかが複雑になることがあります。
    • 特定のGoのバージョンやコンパイラの設定が、ファイルディスクリプタの挙動に影響を与える可能性もゼロではありません。

これらの要因により、TestExtraFilesFDShuffleは特定の環境ではパスするものの、他の環境では不安定になったり、誤って失敗したりする可能性があったため、一時的に無効化するという判断が下されました。これは、テストの信頼性を保ち、開発者がテストの失敗に惑わされることなく開発を進められるようにするための現実的な措置と言えます。

コアとなるコードの変更箇所

--- a/src/pkg/os/exec/exec_test.go
+++ b/src/pkg/os/exec/exec_test.go
@@ -196,6 +196,8 @@ func basefds() uintptr {
 }
 
 func TestExtraFilesFDShuffle(t *testing.T) {
+	t.Skip("TODO: TestExtraFilesFDShuffle is too non-portable; skipping")
+
 	// syscall.StartProcess maps all the FDs passed to it in
 	// ProcAttr.Files (the concatenation of stdin,stdout,stderr and
 	// ExtraFiles) into consecutive FDs in the child, that is:

コアとなるコードの解説

変更はsrc/pkg/os/exec/exec_test.goファイル内のTestExtraFilesFDShuffle関数に対して行われました。

追加された2行は以下の通りです。

	t.Skip("TODO: TestExtraFilesFDShuffle is too non-portable; skipping")
  • t.Skip(): これはGoのテストフレームワーク(testingパッケージ)が提供する関数です。この関数が呼び出されると、現在のテストはスキップされ、テスト結果には「SKIP」として記録されます。テストがスキップされた場合、そのテストは失敗とはみなされません。
  • "TODO: TestExtraFilesFDShuffle is too non-portable; skipping": これはt.Skipに渡されるメッセージで、テストがスキップされた理由を説明します。このメッセージは、テスト結果の出力に表示され、開発者に対してこのテストが一時的に無効化されていること、そしてその理由が「ポータビリティの問題」であることを伝えます。また、「TODO」というプレフィックスは、将来的にこの問題が解決されれば、テストを再度有効化する可能性があることを示唆しています。

この変更により、TestExtraFilesFDShuffleはGoのテストスイートが実行される際に常にスキップされるようになり、ポータビリティの問題に起因する不安定なテスト失敗を防ぐことができます。

関連リンク

参考にした情報源リンク