[インデックス 17617] ファイルの概要
このコミットは、Go言語のnet
パッケージにおけるテストの挙動を改善し、特にWindows環境でのall.bat
スクリプトの実行を、管理者権限を持たない一般ユーザーでも可能にすることを目的としています。具体的には、ネットワーク関連のテストがWindowsのファイアウォールや管理者権限の要件によって失敗する問題を回避するため、特定のテストをスキップする条件を追加しています。
コミット
commit d9fdf88f34f7bfd80e16ed96637ac0b4106d59ed
Author: Russ Cox <rsc@golang.org>
Date: Mon Sep 16 14:05:06 2013 -0400
net: make all.bat run for ordinary Windows users
This CL is required for all.bat to work out of the box on
my Windows 8 laptop.
These tests either require the firewall to be turned off
or require the user to be in the Administrators group.
I don't know which.
Alex may follow up with a refinement of the test to
allow them to run if the user is in the Administrators
group.
Fixes #6392.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/13421049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d9fdf88f34f7bfd80e16ed96637ac0b4106d59ed
元コミット内容
net: make all.bat run for ordinary Windows users
This CL is required for all.bat to work out of the box on
my Windows 8 laptop.
These tests either require the firewall to be turned off
or require the user to be in the Administrators group.
I don't know which.
Alex may follow up with a refinement of the test to
allow them to run if the user is in the Administrators
group.
Fixes #6392.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/13421049
変更の背景
このコミットの主な背景は、Go言語のテストスイート、特にall.bat
スクリプトがWindows環境で管理者権限を持たない一般ユーザーでは正常に実行できないという問題にありました。コミットメッセージによると、Russ Cox氏のWindows 8ラップトップでこの問題が発生しており、ネットワーク関連のテストがWindowsのファイアウォール設定やユーザーの管理者グループへの所属に依存していることが原因と考えられていました。
Go言語の開発プロセスでは、all.bat
(Windowsの場合)やall.bash
(Unix系の場合)のようなスクリプトを実行して、すべてのテストがパスすることを確認することが一般的です。しかし、一部のネットワークテストが特権的な操作(例: RAWソケットの利用、特定のポートへのバインディング、マルチキャスト通信など)を必要とするため、Windowsのセキュリティモデル(ファイアウォールやUAC: User Account Control)によってブロックされることがありました。これにより、開発者がGoのソースコードを変更した際に、テスト環境のセットアップに余計な手間がかかる、あるいはテストが不必要に失敗するといった問題が生じていました。
このコミットは、一時的な解決策として、これらの特権的なネットワークテストを、testing.Short()
フラグが設定されている場合、またはtestExternal
フラグが設定されていない場合にスキップすることで、一般ユーザーでもall.bat
が実行できるようにすることを目指しています。これにより、開発者はより手軽にテストを実行し、開発サイクルをスムーズに進めることができるようになります。将来的には、管理者グループに属しているユーザーに対してはテストを実行できるようにする、といったより洗練された解決策が検討されていました(コミットメッセージ中の「Alex may follow up with a refinement of the test to allow them to run if the user is in the Administrators group.」という記述から伺えます)。
前提知識の解説
このコミットを理解するためには、以下のGo言語のテストフレームワークとWindowsのネットワークに関する基本的な知識が必要です。
testing
パッケージ: Go言語に組み込まれているテストフレームワークです。テスト関数はTest
で始まり、*testing.T
型の引数を取ります。t.Skipf(...)
: テストをスキップするためのメソッドです。指定されたフォーマット文字列と引数でスキップ理由を出力します。testing.Short()
: コマンドラインで-short
フラグが指定された場合にtrue
を返す関数です。通常、実行時間の長いテストや、外部リソースに依存するテストを、CI/CD環境や開発中のクイックテストでスキップするために使用されます。
runtime.GOOS
: Goプログラムが実行されているオペレーティングシステムを示す文字列定数です。例えば、Windowsでは"windows"
、Linuxでは"linux"
、macOSでは"darwin"
となります。これにより、OS固有の処理を条件分岐で記述できます。os.Getuid()
: 現在のプロセスのユーザーIDを返します。Unix系システムでは、rootユーザーの場合に0
を返します。Windowsでは常に-1
を返します。このコミットでは、Unix系システムでroot権限が必要なテストをスキップするために使用されています。*testExternal
: これはGoのテストフレームワークの標準機能ではなく、Goのnet
パッケージのテスト内で定義されているカスタムのフラグ(おそらくflag
パッケージで定義されているグローバル変数)であると推測されます。このフラグがtrue
の場合、外部ネットワークへの接続を伴うテストを実行することを意味していると考えられます。デフォルトではfalse
、つまり外部ネットワークテストは実行しない設定になっている可能性が高いです。- Windowsのファイアウォール: Windowsに組み込まれているセキュリティ機能で、ネットワーク通信を監視し、許可されていない通信をブロックします。特定のポートやプロトコルを使用するアプリケーションは、ファイアウォールによってブロックされることがあります。
- 管理者権限 (Administrators group): Windowsにおけるユーザーアカウントの権限レベルの一つです。管理者グループに属するユーザーは、システム設定の変更、ソフトウェアのインストール、特権的なネットワーク操作など、システム全体に影響を与える操作を実行できます。一般ユーザーはこれらの操作が制限されています。
- RAWソケット: IP層のパケットを直接送受信するためのソケットです。通常のTCP/UDPソケットとは異なり、トランスポート層のプロトコル(TCPやUDP)を介さずに、IPヘッダやペイロードを直接操作できます。セキュリティ上の理由から、RAWソケットの利用は通常、管理者権限を必要とします。このコミットで修正されている
ipraw_test.go
は、RAWソケットを使用するテストを含んでいる可能性が高いです。 - マルチキャスト通信: ネットワーク上で特定のグループに属する複数の受信者に対してデータを一度に送信する通信方式です。マルチキャスト通信も、特定のネットワークインターフェースやルーティング設定に依存するため、環境によっては特権的な操作を必要とすることがあります。
技術的詳細
このコミットは、Go言語のnet
パッケージ内の複数のテストファイルに、Windows環境でのテストスキップ条件を追加することで、all.bat
スクリプトの実行を一般ユーザーでも可能にしています。
変更の核心は、以下の条件式をテスト関数の冒頭に追加することです。
case "windows":
if testing.Short() || !*testExternal {
t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
}
このコードブロックは、以下のロジックで動作します。
case "windows":
: 現在のOSがWindowsである場合にのみ、この条件分岐に入ります。runtime.GOOS
は、コンパイル時または実行時にGoプログラムが動作しているOSを識別するための定数です。if testing.Short() || !*testExternal { ... }
: この条件式がtrue
の場合にテストがスキップされます。testing.Short()
: これはGoのテスト実行時に-short
フラグが指定されているかどうかをチェックします。-short
フラグは、通常、時間のかかるテストや外部依存のあるテストをスキップするために使用されます。開発者がローカルで素早くテストを実行したい場合に利用されます。!*testExternal
: これは、testExternal
というブール型のグローバル変数(ポインタ)がfalse
であるかどうかをチェックします。testExternal
は、おそらく外部ネットワークへの接続を伴うテストを実行するかどうかを制御するカスタムフラグです。デフォルトではfalse
に設定されていることが想定され、これにより外部ネットワークへのアクセスを伴うテストが通常は実行されないようになっています。||
(論理OR): したがって、testing.Short()
がtrue
であるか、またはtestExternal
がfalse
であるかのどちらかの条件が満たされれば、テストはスキップされます。
t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
: 上記の条件がtrue
の場合、t.Skipf
が呼び出され、テストがスキップされます。スキップ理由として「ネットワークファイアウォールを避けるため」と明示されており、これがWindows環境でのテスト失敗の主な原因であったことが示唆されています。
この変更により、Windows環境でall.bat
を実行する際に、デフォルト設定(-short
フラグなし、testExternal
フラグなし)では、特権的なネットワーク操作を必要とするテストがスキップされるようになります。これにより、ファイアウォールや管理者権限の問題に直面することなく、スクリプトが正常に完了する可能性が高まります。
このアプローチは、テストの網羅性を犠牲にする代わりに、開発者の利便性を向上させるトレードオフです。完全なテストを実行するには、ユーザーが明示的に-short
フラグを付けずに、かつtestExternal
フラグをtrue
に設定してテストを実行するか、管理者権限で実行する必要があります。
コアとなるコードの変更箇所
このコミットでは、以下の4つのテストファイルに同様のコードブロックが追加されています。
src/pkg/net/ipraw_test.go
src/pkg/net/multicast_test.go
src/pkg/net/packetconn_test.go
src/pkg/net/protoconn_test.go
具体的な変更箇所は以下の通りです。
src/pkg/net/ipraw_test.go
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -84,6 +84,9 @@ func TestConnICMPEcho(t *testing.T) {
case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
case "windows":
+ if testing.Short() || !*testExternal {
+ t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
+ }
default:
if os.Getuid() != 0 {
t.Skip("skipping test; must be root")
@@ -158,6 +161,9 @@ func TestPacketConnICMPEcho(t *testing.T) {
case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
case "windows":
+ if testing.Short() || !*testExternal {
+ t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
+ }
default:
if os.Getuid() != 0 {
t.Skip("skipping test; must be root")
src/pkg/net/multicast_test.go
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -25,6 +25,10 @@ var ipv4MulticastListenerTests = []struct {
// port.
func TestIPv4MulticastListener(t *testing.T) {
switch runtime.GOOS {
+ case "windows":
+ if testing.Short() || !*testExternal {
+ t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
+ }
case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
}
src/pkg/net/packetconn_test.go
--- a/src/pkg/net/packetconn_test.go
+++ b/src/pkg/net/packetconn_test.go
@@ -32,6 +32,9 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
t.Logf("skipping %q test on %q", net, runtime.GOOS)
}
case "windows":
+ if testing.Short() || !*testExternal {
+ t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
+ }
default:
if os.Getuid() != 0 {
return nil, func() {
src/pkg/net/protoconn_test.go
--- a/src/pkg/net/protoconn_test.go
+++ b/src/pkg/net/protoconn_test.go
@@ -177,6 +177,9 @@ func TestIPConnSpecificMethods(t *testing.T) {
case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
case "windows":
+ if testing.Short() || !*testExternal {
+ t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
+ }
default:
if os.Getuid() != 0 {
t.Skipf("skipping test; must be root")
コアとなるコードの解説
上記の各ファイルに追加されたコードブロックは、Goのテストフレームワークにおける一般的なパターンを示しています。
switch runtime.GOOS
文は、テストが実行されているオペレーティングシステムに基づいて異なる動作をさせるためのGoのイディオムです。これにより、OS固有のテスト要件や制約に対応できます。
case "windows":
ブロック内では、Windows環境に特化したスキップ条件が導入されています。
if testing.Short() || !*testExternal
という条件は、以下のいずれかの状況でテストをスキップすることを意味します。
testing.Short()
がtrue
の場合: これは、ユーザーがgo test -short
コマンドを実行した場合に該当します。このフラグは、通常、開発者が迅速なフィードバックを得るために、時間のかかるテストや外部依存のあるテストを一時的に無効にしたいときに使用されます。ネットワーク関連のテストは外部依存(ネットワーク接続、ファイアウォールなど)が多いため、-short
フラグでスキップされる対象として適切です。!*testExternal
がtrue
の場合: これは、testExternal
というカスタムフラグがfalse
に設定されている場合に該当します。testExternal
は、Goのnet
パッケージのテストスイート内で定義されている変数であり、外部ネットワークへの接続を伴うテストを実行するかどうかを制御するために使用されます。デフォルトではfalse
になっていることが想定され、これにより、通常は外部ネットワークへのアクセスを伴うテストが実行されないようになっています。これは、テスト環境がインターネットに接続されていない場合や、不必要なネットワークトラフィックを避けたい場合に有用です。
これらの条件のいずれかが満たされると、t.Skipf(...)
が呼び出され、テストは実行されずにスキップされます。スキップメッセージには「skipping test on %q to avoid network firewall」と明記されており、Windowsのファイアウォールがテスト失敗の主な原因であったことが示唆されています。
この変更は、Goのテストスイートの堅牢性を高めると同時に、Windowsユーザーの開発体験を向上させるための実用的なアプローチです。特権的なネットワーク操作を必要とするテストは、デフォルトではスキップされることで、一般ユーザーでもall.bat
をスムーズに実行できるようになります。これにより、Go言語のクロスプラットフォーム開発におけるテストの障壁が軽減されます。
関連リンク
- Go Issue 6392: このコミットが修正したGoのIssueです。
- Gerrit Change 13421049: このコミットに対応するGerritの変更セットです。
参考にした情報源リンク
- Go の testing パッケージ - Qiita
- Go言語のテスト入門 - Qiita
- Go言語のテストで -short フラグを使う - Qiita
- Go言語のruntimeパッケージのGOOS定数 - Qiita
- Windows ファイアウォールとは - Microsoft Support
- RAWソケット - Wikipedia
- マルチキャスト - Wikipedia
- Go言語のテストにおける外部依存の扱い - Qiita (これは一般的な情報源であり、
testExternal
フラグの具体的な定義についてはGoのソースコードを参照する必要がありますが、概念的な理解に役立ちます。) - Go言語のテストにおける環境変数とフラグの利用 - Qiita