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

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

このコミットは、Go言語の標準ライブラリnetパッケージ内のTestSelfConnectテストにおいて、Dial関数の代わりにDialTimeout関数を使用するように変更するものです。これにより、ネットワーク接続が確立されない場合にシステムがタイムアウトするまでの時間を短縮し、テストの信頼性と効率を向上させることが目的です。特に、何もリッスンしていないアドレスへの接続試行が長時間かかるシステムでの問題を回避しつつ、自己接続(self-connect)の誤動作を迅速に検出できるようにします。

コミット

  • コミットハッシュ: 4aa521a77d1fdc36d68f9ad2591bb28addb327e5
  • Author: Ian Lance Taylor iant@golang.org
  • Date: Fri Dec 27 08:49:47 2013 -0800

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

https://github.com/golang/go/commit/4aa521a77d1fdc36d68f9ad2591bb28addb327e5

元コミット内容

net: use DialTimeout in TestSelfConnect

This avoids problems with systems that take a long time to
find out nothing is listening, while still testing for the
self-connect misfeature since a self-connect should be fast.
With this we may be able to remove the test for non-Linux
systems.

Tested (on GNU/Linux) by editing selfConnect in
tcpsock_posix.go to always return false and verifying that
TestSelfConnect then fails with and without this change.

Idea from Uros Bizjak.

R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/39200044

変更の背景

netパッケージのTestSelfConnectテストは、特定のネットワーク条件下での自己接続(self-connect)の挙動を検証するために存在します。自己接続とは、クライアントが自分自身(同じマシン上のポート)に接続しようとするシナリオを指します。このテストの目的は、意図しない自己接続が発生しないことを確認すること、または自己接続が発生した場合にそれが迅速に検出されることを保証することです。

しかし、従来のDial関数を使用した場合、何もリッスンしていないポートへの接続試行が、一部のシステム(特に非Linuxシステム)で非常に長い時間を要することがありました。これは、OSのTCP/IPスタックが接続失敗を報告するまでの内部的なタイムアウト設定に依存するためです。テストが長時間ハングアップしたり、不必要に実行時間が長くなったりする原因となっていました。

この問題に対処するため、コミットの著者はDialTimeoutの使用を提案しました。DialTimeoutは、接続試行に明示的なタイムアウトを設定できるため、テストが不必要に待機する時間を短縮し、テストの実行効率と信頼性を向上させることができます。これにより、テストがより迅速に失敗を検出し、開発サイクルを加速させることが期待されます。また、この変更により、将来的には非Linuxシステム向けの特定のテストケースを削除できる可能性も示唆されています。

前提知識の解説

1. Go言語のnetパッケージ

Go言語のnetパッケージは、ネットワークI/Oのプリミティブを提供します。TCP/IP、UDP、Unixドメインソケットなどのネットワークプロトコルを扱うための機能が含まれています。

  • net.Dial: 指定されたネットワークアドレスへの接続を確立します。例えば、Dial("tcp", "localhost:8080")はTCPプロトコルを使用してlocalhostのポート8080に接続を試みます。接続が確立されるまでブロックします。
  • net.DialTimeout: Dialと同様に接続を確立しますが、接続試行に最大時間を設定できます。指定されたタイムアウト時間内に接続が確立されない場合、エラーを返します。これは、ネットワークの応答が遅い場合や、接続先が存在しない場合に、アプリケーションが無限に待機するのを防ぐために非常に重要です。

2. TCP自己接続(Self-Connect)

TCP自己接続とは、クライアントが自分自身(通常は同じIPアドレスとポート番号)に接続しようとするネットワークの挙動です。これは通常、意図しない設定ミスやバグによって発生します。例えば、サーバーアプリケーションが特定のポートでリッスンしているにもかかわらず、クライアントがその同じポートに接続しようとする場合などです。

自己接続は、TCP/IPスタックの実装やOSの挙動によって、許可されたり、拒否されたり、あるいは特定の条件下で異なる挙動を示したりすることがあります。TestSelfConnectのようなテストは、このようなエッジケースでのシステムの挙動を検証し、予期せぬ問題を防ぐために重要です。

3. テスト駆動開発とテストの重要性

ソフトウェア開発において、テストはコードの品質、信頼性、および保守性を保証するために不可欠です。Go言語は、標準ライブラリにtestingパッケージを提供しており、ユニットテスト、ベンチマークテスト、および例(Example)テストを簡単に記述できます。

  • ユニットテスト: 個々の関数やメソッドが期待通りに動作するかを検証します。
  • 統合テスト: 複数のコンポーネントが連携して正しく動作するかを検証します。
  • 回帰テスト: 以前に修正されたバグが再発していないことを確認します。

このコミットで変更されるTestSelfConnectは、netパッケージの特定のネットワーク挙動を検証する統合テストの一種と見なせます。テストの実行速度は、開発サイクルにおいて非常に重要です。テストが遅いと、開発者はテストを実行する頻度が減り、結果としてバグの早期発見が遅れる可能性があります。

技術的詳細

このコミットの核心は、net.Dialからnet.DialTimeoutへの変更です。この変更がもたらす技術的な影響は以下の通りです。

  1. タイムアウトによるテストの高速化と信頼性向上:

    • 従来のDial関数は、接続が確立されるか、OSの内部的なタイムアウトが発生するまでブロックします。何もリッスンしていないポートへの接続試行は、OSによっては数秒から数十秒かかることがあり、これがテストの実行時間を不必要に長くしていました。
    • DialTimeoutを使用することで、接続試行に明示的にtime.Millisecond(1ミリ秒)という非常に短いタイムアウトを設定しています。これにより、何もリッスンしていないポートへの接続試行が、設定されたタイムアウト時間(1ミリ秒)を超えるとすぐにエラーを返すようになります。
    • 結果として、テストが失敗するまでの時間が大幅に短縮され、テストスイート全体の実行速度が向上します。これはCI/CDパイプラインにおいて特に重要であり、迅速なフィードバックループを可能にします。
  2. 自己接続テストの意図の明確化:

    • コミットメッセージにあるように、「自己接続は高速であるべき」という前提があります。つまり、もし自己接続が意図せず発生した場合、それはすぐに検出されるべきであり、長時間待機する必要はありません。
    • DialTimeoutを短い時間で設定することで、この「高速であるべき」という前提をコードレベルで強制し、テストの意図をより明確にしています。もし自己接続が1ミリ秒以内に完了しない場合、それは異常と見なされ、テストは失敗します。
  3. 非Linuxシステムにおけるテストの簡素化の可能性:

    • コミットメッセージでは、「With this we may be able to remove the test for non-Linux systems.」と述べられています。これは、従来のDialが非Linuxシステムで特に遅延を引き起こしていたため、それらのシステム向けに特別なテストロジックや条件分岐が必要だった可能性を示唆しています。
    • DialTimeoutの導入により、OS間の挙動の差異が吸収され、すべてのシステムで一貫した高速なタイムアウト挙動が期待できるようになります。これにより、特定のOSに特化したテストケースが不要になり、テストコードの簡素化と保守性の向上が見込まれます。
  4. テストの検証方法:

    • コミットメッセージには、この変更がどのようにテストされたかが具体的に記述されています。「Tested (on GNU/Linux) by editing selfConnect in tcpsock_posix.go to always return false and verifying that TestSelfConnect then fails with and without this change.」
    • これは、tcpsock_posix.goファイル内のselfConnect関数(おそらく自己接続の検出ロジックを制御する内部関数)を意図的にfalseを返すように変更し、TestSelfConnectが期待通りに失敗することを確認したことを意味します。この検証は、DialTimeoutの導入がテストの意図を損なうことなく、むしろ改善していることを裏付けています。

この変更は、単なる関数呼び出しの置き換え以上の意味を持ち、Goのネットワークテストの堅牢性と効率性を向上させるための重要な改善です。

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

変更はsrc/pkg/net/dial_test.goファイルの一箇所のみです。

--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -147,7 +147,7 @@ func TestSelfConnect(t *testing.T) {
 		n = 100
 	}
 	for i := 0; i < n; i++ {
-		c, err := Dial("tcp", addr)
+		c, err := DialTimeout("tcp", addr, time.Millisecond)
 		if err == nil {
 			c.Close()
 			t.Errorf("#%d: Dial %q succeeded", i, addr)

コアとなるコードの解説

変更された行は、TestSelfConnect関数内のループの中です。

  • 変更前:

    c, err := Dial("tcp", addr)
    

    ここでは、net.Dial関数が使用されており、TCPプロトコルで指定されたaddr(アドレス)への接続を試みています。この呼び出しは、接続が確立されるか、OSが接続失敗を報告するまでブロックします。

  • 変更後:

    c, err := DialTimeout("tcp", addr, time.Millisecond)
    

    変更後には、net.DialTimeout関数が使用されています。引数として"tcp"(プロトコル)、addr(アドレス)、そしてtime.Millisecond(1ミリ秒)というタイムアウト値が渡されています。 この変更により、接続試行は最大1ミリ秒でタイムアウトするようになります。もし1ミリ秒以内に接続が確立されない場合、DialTimeoutはエラーを返し、テストは迅速に次の処理に進むか、エラーを報告して失敗します。

このシンプルな変更により、何もリッスンしていないポートへの接続試行が長時間ブロックされる問題が解決され、TestSelfConnectの実行効率と信頼性が大幅に向上しました。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語の標準ライブラリnetパッケージ内のTestSelfConnectテストにおいて、Dial関数の代わりにDialTimeout関数を使用するように変更するものです。これにより、ネットワーク接続が確立されない場合にシステムがタイムアウトするまでの時間を短縮し、テストの信頼性と効率を向上させることが目的です。特に、何もリッスンしていないアドレスへの接続試行が長時間かかるシステムでの問題を回避しつつ、自己接続(self-connect)の誤動作を迅速に検出できるようにします。

コミット

  • コミットハッシュ: 4aa521a77d1fdc36d68f9ad2591bb28addb327e5
  • Author: Ian Lance Taylor iant@golang.org
  • Date: Fri Dec 27 08:49:47 2013 -0800

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

https://github.com/golang/go/commit/4aa521a77d1fdc36d68f9ad2591bb28addb327e5

元コミット内容

net: use DialTimeout in TestSelfConnect

This avoids problems with systems that take a long time to
find out nothing is listening, while still testing for the
self-connect misfeature since a self-connect should be fast.
With this we may be able to remove the test for non-Linux
systems.

Tested (on GNU/Linux) by editing selfConnect in
tcpsock_posix.go to always return false and verifying that
TestSelfConnect then fails with and without this change.

Idea from Uros Bizjak.

R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/39200044

変更の背景

netパッケージのTestSelfConnectテストは、特定のネットワーク条件下での自己接続(self-connect)の挙動を検証するために存在します。自己接続とは、クライアントが自分自身(同じマシン上のポート)に接続しようとするシナリオを指します。このテストの目的は、意図しない自己接続が発生しないことを確認すること、または自己接続が発生した場合にそれが迅速に検出されることを保証することです。

しかし、従来のDial関数を使用した場合、何もリッスンしていないポートへの接続試行が、一部のシステム(特に非Linuxシステム)で非常に長い時間を要することがありました。これは、OSのTCP/IPスタックが接続失敗を報告するまでの内部的なタイムアウト設定に依存するためです。テストが長時間ハングアップしたり、不必要に実行時間が長くなったりする原因となっていました。

この問題に対処するため、コミットの著者はDialTimeoutの使用を提案しました。DialTimeoutは、接続試行に明示的なタイムアウトを設定できるため、テストが不必要に待機する時間を短縮し、テストの実行効率と信頼性を向上させることができます。これにより、テストがより迅速に失敗を検出し、開発サイクルを加速させることが期待されます。また、この変更により、将来的には非Linuxシステム向けの特定のテストケースを削除できる可能性も示唆されています。

前提知識の解説

1. Go言語のnetパッケージ

Go言語のnetパッケージは、ネットワークI/Oのプリミティブを提供します。TCP/IP、UDP、Unixドメインソケットなどのネットワークプロトコルを扱うための機能が含まれています。

  • net.Dial: 指定されたネットワークアドレスへの接続を確立します。例えば、Dial("tcp", "localhost:8080")はTCPプロトコルを使用してlocalhostのポート8080に接続を試みます。接続が確立されるまでブロックします。
  • net.DialTimeout: Dialと同様に接続を確立しますが、接続試行に最大時間を設定できます。指定されたタイムアウト時間内に接続が確立されない場合、エラーを返します。これは、ネットワークの応答が遅い場合や、接続先が存在しない場合に、アプリケーションが無限に待機するのを防ぐために非常に重要です。

2. TCP自己接続(Self-Connect)

TCP自己接続とは、クライアントが自分自身(通常は同じIPアドレスとポート番号)に接続しようとするネットワークの挙動です。これは通常、意図しない設定ミスやバグによって発生します。例えば、サーバーアプリケーションが特定のポートでリッスンしているにもかかわらず、クライアントがその同じポートに接続しようとする場合などです。

自己接続は、TCP/IPスタックの実装やOSの挙動によって、許可されたり、拒否されたり、あるいは特定の条件下で異なる挙動を示したりすることがあります。TestSelfConnectのようなテストは、このようなエッジケースでのシステムの挙動を検証し、予期せぬ問題を防ぐために重要です。

3. テスト駆動開発とテストの重要性

ソフトウェア開発において、テストはコードの品質、信頼性、および保守性を保証するために不可欠です。Go言語は、標準ライブラリにtestingパッケージを提供しており、ユニットテスト、ベンチマークテスト、および例(Example)テストを簡単に記述できます。

  • ユニットテスト: 個々の関数やメソッドが期待通りに動作するかを検証します。
  • 統合テスト: 複数のコンポーネントが連携して正しく動作するかを検証します。
  • 回帰テスト: 以前に修正されたバグが再発していないことを確認します。

このコミットで変更されるTestSelfConnectは、netパッケージの特定のネットワーク挙動を検証する統合テストの一種と見なせます。テストの実行速度は、開発サイクルにおいて非常に重要です。テストが遅いと、開発者はテストを実行する頻度が減り、結果としてバグの早期発見が遅れる可能性があります。

技術的詳細

このコミットの核心は、net.Dialからnet.DialTimeoutへの変更です。この変更がもたらす技術的な影響は以下の通りです。

  1. タイムアウトによるテストの高速化と信頼性向上:

    • 従来のDial関数は、接続が確立されるか、OSの内部的なタイムアウトが発生するまでブロックします。何もリッスンしていないポートへの接続試行は、OSによっては数秒から数十秒かかることがあり、これがテストの実行時間を不必要に長くしていました。
    • DialTimeoutを使用することで、接続試行に明示的にtime.Millisecond(1ミリ秒)という非常に短いタイムアウトを設定しています。これにより、何もリッスンしていないポートへの接続試行が、設定されたタイムアウト時間(1ミリ秒)を超えるとすぐにエラーを返すようになります。
    • 結果として、テストが失敗するまでの時間が大幅に短縮され、テストスイート全体の実行速度が向上します。これはCI/CDパイプラインにおいて特に重要であり、迅速なフィードバックループを可能にします。
  2. 自己接続テストの意図の明確化:

    • コミットメッセージにあるように、「自己接続は高速であるべき」という前提があります。つまり、もし自己接続が意図せず発生した場合、それはすぐに検出されるべきであり、長時間待機する必要はありません。
    • DialTimeoutを短い時間で設定することで、この「高速であるべき」という前提をコードレベルで強制し、テストの意図をより明確にしています。もし自己接続が1ミリ秒以内に完了しない場合、それは異常と見なされ、テストは失敗します。
  3. 非Linuxシステムにおけるテストの簡素化の可能性:

    • コミットメッセージでは、「With this we may be able to remove the test for non-Linux systems.」と述べられています。これは、従来のDialが非Linuxシステムで特に遅延を引き起こしていたため、それらのシステム向けに特別なテストロジックや条件分岐が必要だった可能性を示唆しています。
    • DialTimeoutの導入により、OS間の挙動の差異が吸収され、すべてのシステムで一貫した高速なタイムアウト挙動が期待できるようになります。これにより、特定のOSに特化したテストケースが不要になり、テストコードの簡素化と保守性の向上が見込まれます。
  4. テストの検証方法:

    • コミットメッセージには、この変更がどのようにテストされたかが具体的に記述されています。「Tested (on GNU/Linux) by editing selfConnect in tcpsock_posix.go to always return false and verifying that TestSelfConnect then fails with and without this change.」
    • これは、tcpsock_posix.goファイル内のselfConnect関数(おそらく自己接続の検出ロジックを制御する内部関数)を意図的にfalseを返すように変更し、TestSelfConnectが期待通りに失敗することを確認したことを意味します。この検証は、DialTimeoutの導入がテストの意図を損なうことなく、むしろ改善していることを裏付けています。

この変更は、単なる関数呼び出しの置き換え以上の意味を持ち、Goのネットワークテストの堅牢性と効率性を向上させるための重要な改善です。

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

変更はsrc/pkg/net/dial_test.goファイルの一箇所のみです。

--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -147,7 +147,7 @@ func TestSelfConnect(t *testing.T) {
 		n = 100
 	}
 	for i := 0; i < n; i++ {
-		c, err := Dial("tcp", addr)
+		c, err := DialTimeout("tcp", addr, time.Millisecond)
 		if err == nil {
 			c.Close()
 			t.Errorf("#%d: Dial %q succeeded", i, addr)

コアとなるコードの解説

変更された行は、TestSelfConnect関数内のループの中です。

  • 変更前:

    c, err := Dial("tcp", addr)
    

    ここでは、net.Dial関数が使用されており、TCPプロトコルで指定されたaddr(アドレス)への接続を試みています。この呼び出しは、接続が確立されるか、OSが接続失敗を報告するまでブロックします。

  • 変更後:

    c, err := DialTimeout("tcp", addr, time.Millisecond)
    

    変更後には、net.DialTimeout関数が使用されています。引数として"tcp"(プロトコル)、addr(アドレス)、そしてtime.Millisecond(1ミリ秒)というタイムアウト値が渡されています。 この変更により、接続試行は最大1ミリ秒でタイムアウトするようになります。もし1ミリ秒以内に接続が確立されない場合、DialTimeoutはエラーを返し、テストは迅速に次の処理に進むか、エラーを報告して失敗します。

このシンプルな変更により、何もリッスンしていないポートへの接続試行が長時間ブロックされる問題が解決され、TestSelfConnectの実行効率と信頼性が大幅に向上しました。

関連リンク

参考にした情報源リンク