[インデックス 18602] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるUnix系システム向けのテストケースの整理と統合を目的としています。具体的には、既存の複数のテストファイルを一つのファイルに集約し、テストコードの管理と保守を効率化しています。
コミット
commit 2dcf8593acbacc36b970be859711c97e4f266b35
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Mon Feb 24 14:41:10 2014 +0900
syscall: consolidate test cases for Unix-like systems
As per request from minux in CL 61520049, this CL consolidates
existing test cases for Unix-like systems into one file except
Linux-specific credential test.
LGTM=bradfitz
R=iant, minux.ma, bradfitz
CC=golang-codereviews
https://golang.org/cl/67800044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2dcf8593acbacc36b970be859711c97e4f266b35
元コミット内容
このコミットの元々の内容は、syscall
パッケージにおけるUnix系システム向けのテストケースを統合することです。具体的には、src/pkg/syscall/consistency_unix_test.go
とsrc/pkg/syscall/rlimit_unix_test.go
のテストコードを、src/pkg/syscall/passfd_test.go
をリネームしたsrc/pkg/syscall/syscall_unix_test.go
に移動・統合しています。ただし、Linux固有のクレデンシャルテストは統合の対象外とされています。
変更の背景
この変更の背景には、minux
氏からのリクエスト(CL 61520049)があります。Goの標準ライブラリ、特にsyscall
パッケージのようにOS固有の機能と密接に関わる部分では、様々なUnix系システム(FreeBSD, Dragonfly BSD, Darwin (macOS), Linux, NetBSD, OpenBSDなど)に対応するためのテストが多数存在します。これらのテストが複数のファイルに分散していると、管理が煩雑になり、新しいテストの追加や既存テストの修正、あるいは全体的なテストカバレッジの把握が困難になる可能性があります。
テストケースを一つのファイルに集約することで、以下のようなメリットが期待されます。
- 保守性の向上: 関連するテストが同じ場所にあるため、変更が必要な際に探しやすくなります。
- 可読性の向上: テストの全体像を把握しやすくなり、コードレビューも効率的になります。
- テスト実行の効率化: 複数のテストファイルを個別にコンパイル・実行するオーバーヘッドが削減される可能性があります。
- 一貫性の確保: テストの記述スタイルやプラットフォームごとのビルドタグ(
+build
ディレクティブ)の一貫性を保ちやすくなります。
このコミットは、これらの課題を解決し、syscall
パッケージのテスト基盤をより堅牢で管理しやすいものにすることを目的としています。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
Go言語のsyscall
パッケージ
syscall
パッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。システムコールは、ファイルI/O、ネットワーク通信、プロセス管理、メモリ管理など、OSカーネルが提供する基本的なサービスを利用するために使用されます。Goの標準ライブラリの多くの高レベルな機能(例: os
パッケージ、net
パッケージ)は、内部的にこのsyscall
パッケージを利用しています。
syscall
パッケージはOSに強く依存するため、Unix系システム(Linux, macOS, BSDなど)、Windows、Plan 9など、各OSプラットフォーム向けに異なる実装を持っています。これにより、Goプログラムはクロスプラットフォームで動作しつつも、必要に応じてOS固有の機能を利用できます。
Unix系システム
Unix系システムとは、Unixオペレーティングシステムの設計思想や機能セットを継承したOSの総称です。Linux、macOS (Darwin)、FreeBSD、OpenBSD、NetBSD、Solarisなどが含まれます。これらのシステムは、ファイルシステム構造、プロセス管理、システムコールインターフェースなどにおいて共通の概念やAPIを多く持っています。
Goのsyscall
パッケージでは、これらのUnix系システム間で共通して利用できるシステムコールやデータ構造(例: Flock_t
、Rlimit
)に対するテストが重要になります。
Goのテストフレームワーク
Goには標準で強力なテストフレームワークが組み込まれています。
testing
パッケージ: Goのテストは、_test.go
で終わるファイルに記述され、testing
パッケージを利用します。テスト関数はTestXxx
という命名規則に従い、*testing.T
型の引数を取ります。- ビルドタグ (
+build
ディレクティブ): Goのソースファイルには、ファイルの先頭に// +build tag
のようなコメントを記述することで、特定のビルド条件(OS、アーキテクチャ、カスタムタグなど)が満たされた場合にのみそのファイルをコンパイル対象とするように指定できます。このコミットでは、+build freebsd dragonfly darwin linux netbsd openbsd
というタグが使用されており、これは指定されたUnix系OSでのみテストが実行されることを意味します。 go test
コマンド:go test
コマンドは、プロジェクト内のテストファイルを自動的に発見し、実行します。
RLIMIT_NOFILE
とGetrlimit
/Setrlimit
RLIMIT_NOFILE
は、プロセスがオープンできるファイルディスクリプタの最大数を制限するリソースリミットの一つです。Unix系システムでは、getrlimit
およびsetrlimit
システムコールを使用して、プロセスのリソース制限(ソフトリミットとハードリミット)を取得および設定できます。
- ソフトリミット (soft limit): 現在適用されている制限で、プロセスはこの値を超えてリソースを使用できません。
- ハードリミット (hard limit): ソフトリミットの最大値で、特権プロセス(rootなど)のみがハードリミットを増やすことができます。非特権プロセスはソフトリミットをハードリミット以下に減らすことしかできません。
TestRlimit
関数は、これらのシステムコールが正しく機能するかどうかをテストしています。
passfd
(File Descriptor Passing)
passfd
は、Unixドメインソケットを介してプロセス間でファイルディスクリプタ(FD)を渡すメカニズムです。これにより、異なるプロセスが同じファイルやソケットにアクセスできるようになります。これは、特権分離や効率的なリソース共有に利用されます。TestPassFD
関数は、このFDの受け渡し機能が正しく動作するかを検証しています。
技術的詳細
このコミットの主要な技術的変更は、複数のテストファイルを一つに統合することです。
-
ファイルの削除:
src/pkg/syscall/consistency_unix_test.go
: このファイルは、Unix系システム間で共通のsyscall
の定数や関数(Setpriority
,Getpriority
,PRIO_USER
,PRIO_PROCESS
,PRIO_PGRP
,TCIFLUSH
,TCIOFLUSH
,TCOFLUSH
,Flock_t
構造体など)の存在と型の一貫性をテストしていました。src/pkg/syscall/rlimit_unix_test.go
: このファイルは、RLIMIT_NOFILE
に対するGetrlimit
とSetrlimit
システムコールの動作をテストしていました。
-
ファイルのリネームと統合:
src/pkg/syscall/passfd_test.go
がsrc/pkg/syscall/syscall_unix_test.go
にリネームされました。- 削除された
consistency_unix_test.go
とrlimit_unix_test.go
の内容が、新しくリネームされたsyscall_unix_test.go
に移動・追加されました。
-
ビルドタグの調整:
passfd_test.go
のビルドタグは+build linux dragonfly darwin freebsd netbsd openbsd
でしたが、統合後のsyscall_unix_test.go
では+build freebsd dragonfly darwin linux netbsd openbsd
に変更されています。これは、consistency_unix_test.go
のタグと一致させることで、統合されたテストが意図したすべてのUnix系システムで実行されるようにするためです。- 新しい
syscall_unix_test.go
には、consistency_unix_test.go
にあったコメント// This file tests that some basic syscalls are consistent across // all Unixes.
が追加され、ファイルの目的が明確化されています。
-
テストロジックの移動:
consistency_unix_test.go
内の_()
関数(Goでは、_
に代入することで、変数が使用されていないというコンパイラエラーを回避しつつ、型や定数の存在を確認するイディオムとして使われることがあります)がsyscall_unix_test.go
に移動されました。rlimit_unix_test.go
内のTestRlimit
関数がsyscall_unix_test.go
に移動されました。
-
Linux固有のテストの除外: コミットメッセージにある通り、Linux固有のクレデンシャルテストは統合の対象外とされています。これは、特定のOSに強く依存するテストは、そのOS専用のテストファイルに残しておく方が管理しやすいという判断があったためと考えられます。
この統合により、Unix系システム向けの一般的なsyscall
テストはsyscall_unix_test.go
という単一のエントリポイントからアクセスできるようになり、テストコードの構造がより整理されました。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、主に以下の3つのファイルにわたります。
-
src/pkg/syscall/consistency_unix_test.go
: このファイルが削除されました。- 削除された内容:
Setpriority
,Getpriority
,PRIO_USER
,PRIO_PROCESS
,PRIO_PGRP
などの優先度関連の関数と定数の型チェック。TCIFLUSH
,TCIOFLUSH
,TCOFLUSH
などのtermios関連の定数の型チェック。Flock_t
構造体の型チェック。
- 削除された内容:
-
src/pkg/syscall/rlimit_unix_test.go
: このファイルが削除されました。- 削除された内容:
TestRlimit
関数:RLIMIT_NOFILE
に対するGetrlimit
とSetrlimit
の動作をテストする関数。
- 削除された内容:
-
src/pkg/syscall/passfd_test.go
: このファイルがsrc/pkg/syscall/syscall_unix_test.go
にリネームされ、上記2つのファイルの内容が追加されました。- リネーム前の内容(
TestPassFD
,TestUnixRightsRoundtrip
など)はそのまま維持。 - 追加された内容:
consistency_unix_test.go
から移動された、優先度、termios、Flock_t
に関する型チェックの_()
関数群。rlimit_unix_test.go
から移動されたTestRlimit
関数。- ファイルの先頭に
// This file tests that some basic syscalls are consistent across // all Unixes.
というコメントが追加。 - ビルドタグが
+build freebsd dragonfly darwin linux netbsd openbsd
に更新。 TestPassFD
内のt.Skip("Skipping test on dragonfly")
がt.Skip("skipping test on dragonfly")
に修正(メッセージの小文字化)。
- リネーム前の内容(
コアとなるコードの解説
統合されたsyscall_unix_test.go
ファイルは、Unix系システムにおけるsyscall
パッケージの基本的な機能と一貫性を検証するための包括的なテストスイートとなります。
_()
関数群 (旧 consistency_unix_test.go
からの移動)
// {Set,Get}priority and needed constants for them
func _() {
var (
_ func(int, int, int) error = syscall.Setpriority
_ func(int, int) (int, error) = syscall.Getpriority
)
const (
_ int = syscall.PRIO_USER
_ int = syscall.PRIO_PROCESS
_ int = syscall.PRIO_PGRP
)
}
// termios functions and constants
func _() {
const (
_ int = syscall.TCIFLUSH
_ int = syscall.TCIOFLUSH
_ int = syscall.TCOFLUSH
)
}
func _() {
_ = syscall.Flock_t{
Type: int16(0),
Whence: int16(0),
Start: int64(0),
Len: int64(0),
Pid: int32(0),
}
}
これらの_()
関数は、Goのコンパイラの型チェックを利用して、特定のシステムコール関数、定数、および構造体が、Goのsyscall
パッケージ内で期待されるシグネチャと型で定義されていることを検証します。これは、異なるUnix系システム間でsyscall
パッケージの実装に一貫性があることを保証するための基本的なテストです。例えば、syscall.Setpriority
がfunc(int, int, int) error
というシグネチャを持つことを確認しています。もし、いずれかのOSでこれらの定義が異なると、コンパイルエラーが発生し、互換性の問題が早期に発見されます。
TestRlimit
関数 (旧 rlimit_unix_test.go
からの移動)
func TestRlimit(t *testing.T) {
var rlimit, zero syscall.Rlimit
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
if err != nil {
t.Fatalf("Getrlimit: save failed: %v", err)
}
if zero == rlimit {
t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
}
set := rlimit
set.Cur = set.Max - 1
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
if err != nil {
t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
}
var get syscall.Rlimit
err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
if err != nil {
t.Fatalf("Getrlimit: get failed: %v", err)
}
set = rlimit
set.Cur = set.Max - 1
if set != get {
// Seems like Darwin requires some privilege to
// increase the soft limit of rlimit sandbox, though
// Setrlimit never reports an error.
switch runtime.GOOS {
case "darwin":
default:
t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
}
}
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
if err != nil {
t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
}
}
このテスト関数は、Unix系システムにおけるファイルディスクリプタのリソース制限(RLIMIT_NOFILE
)の操作が正しく行われるかを検証します。
- 現在のリミットの取得と保存:
syscall.Getrlimit
を呼び出して、現在のRLIMIT_NOFILE
のソフトリミットとハードリミットを取得し、rlimit
変数に保存します。取得が失敗したり、ゼロ値が返されたりしないことを確認します。 - ソフトリミットの変更: 取得した
rlimit
のコピー(set
)を作成し、ソフトリミット(set.Cur
)をハードリミット(set.Max
)より1つ小さい値に設定します。そして、syscall.Setrlimit
を呼び出してこの新しい制限を設定します。 - 変更の検証: 再度
syscall.Getrlimit
を呼び出して、設定した制限が正しく反映されているかを確認します。 - Darwin特有の挙動の考慮: Darwin(macOS)では、
Setrlimit
がエラーを報告しないにもかかわらず、ソフトリミットの増加に特権が必要な場合があるため、このOSではリミットの変更が期待通りに行われなくてもテストを失敗させないように特別な処理が記述されています。 - 元のリミットへの復元: テストの最後に、最初に保存した
rlimit
の値を使って元のリソース制限に戻します。これは、テストがシステムの状態を汚染しないようにするための重要なステップです。
このテストは、syscall
パッケージが提供するリソースリミット管理機能が、異なるUnix系システムで期待通りに動作することを保証します。
関連リンク
- Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - Go言語の
testing
パッケージのドキュメント: https://pkg.go.dev/testing - Unixドメインソケット (Wikipedia): https://ja.wikipedia.org/wiki/Unix%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%BD%E3%82%B1%E3%83%83%E3%83%88
getrlimit(2)
man page (Linux): https://man7.org/linux/man-pages/man2/getrlimit.2.html
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- Go Code Review Comments (ビルドタグについて): https://go.dev/doc/effective_go#build_tags
- Goのテストに関する公式ドキュメント: https://go.dev/doc/tutorial/add-a-test
- CL 61520049 (コミットメッセージで言及されているminux氏のリクエスト): このCLはGoの公開リポジトリには見つかりませんでしたが、内部的なコードレビューシステムでのやり取りを示唆しています。
- CL 67800044 (このコミットに対応するGoのコードレビュー): https://golang.org/cl/67800044