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

[インデックス 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)
    }

このコードブロックは、以下のロジックで動作します。

  1. case "windows":: 現在のOSがWindowsである場合にのみ、この条件分岐に入ります。runtime.GOOSは、コンパイル時または実行時にGoプログラムが動作しているOSを識別するための定数です。
  2. if testing.Short() || !*testExternal { ... }: この条件式がtrueの場合にテストがスキップされます。
    • testing.Short(): これはGoのテスト実行時に-shortフラグが指定されているかどうかをチェックします。-shortフラグは、通常、時間のかかるテストや外部依存のあるテストをスキップするために使用されます。開発者がローカルで素早くテストを実行したい場合に利用されます。
    • !*testExternal: これは、testExternalというブール型のグローバル変数(ポインタ)がfalseであるかどうかをチェックします。testExternalは、おそらく外部ネットワークへの接続を伴うテストを実行するかどうかを制御するカスタムフラグです。デフォルトではfalseに設定されていることが想定され、これにより外部ネットワークへのアクセスを伴うテストが通常は実行されないようになっています。
    • || (論理OR): したがって、testing.Short()trueであるか、またはtestExternalfalseであるかのどちらかの条件が満たされれば、テストはスキップされます。
  3. 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つのテストファイルに同様のコードブロックが追加されています。

  1. src/pkg/net/ipraw_test.go
  2. src/pkg/net/multicast_test.go
  3. src/pkg/net/packetconn_test.go
  4. 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という条件は、以下のいずれかの状況でテストをスキップすることを意味します。

  1. testing.Short()trueの場合: これは、ユーザーがgo test -shortコマンドを実行した場合に該当します。このフラグは、通常、開発者が迅速なフィードバックを得るために、時間のかかるテストや外部依存のあるテストを一時的に無効にしたいときに使用されます。ネットワーク関連のテストは外部依存(ネットワーク接続、ファイアウォールなど)が多いため、-shortフラグでスキップされる対象として適切です。
  2. !*testExternaltrueの場合: これは、testExternalというカスタムフラグがfalseに設定されている場合に該当します。testExternalは、Goのnetパッケージのテストスイート内で定義されている変数であり、外部ネットワークへの接続を伴うテストを実行するかどうかを制御するために使用されます。デフォルトではfalseになっていることが想定され、これにより、通常は外部ネットワークへのアクセスを伴うテストが実行されないようになっています。これは、テスト環境がインターネットに接続されていない場合や、不必要なネットワークトラフィックを避けたい場合に有用です。

これらの条件のいずれかが満たされると、t.Skipf(...)が呼び出され、テストは実行されずにスキップされます。スキップメッセージには「skipping test on %q to avoid network firewall」と明記されており、Windowsのファイアウォールがテスト失敗の主な原因であったことが示唆されています。

この変更は、Goのテストスイートの堅牢性を高めると同時に、Windowsユーザーの開発体験を向上させるための実用的なアプローチです。特権的なネットワーク操作を必要とするテストは、デフォルトではスキップされることで、一般ユーザーでもall.batをスムーズに実行できるようになります。これにより、Go言語のクロスプラットフォーム開発におけるテストの障壁が軽減されます。

関連リンク

参考にした情報源リンク