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

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

このコミットは、Go言語の標準ライブラリnetパッケージ内のhosts_test.goファイルに対する変更です。具体的には、TestLookupStaticHostテスト関数におけるエラー処理の改善を目的としています。

コミット

commit cf51702bba18cf15e4f4aca1db6bf33bfa349d64
Author: Josh Bleecher Snyder <josharian@gmail.com>
Date:   Thu Dec 12 10:12:06 2013 +0400

    net: don't leave hostsPath unrestored on error in TestLookupStaticHost
    
    If the return was reached, then hostsPath would not be properly restored
    to its original value. See the (lengthy) discussion at
    https://golang.org/cl/15960047/
    
    I assume that this is not for Go 1.2; mailing now since I promised to do so.
    I will plan to ping once Go 1.2 is out.
    
    R=rsc, bradfitz
    CC=golang-dev
    https://golang.org/cl/16200043
---
 src/pkg/net/hosts_test.go | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n
diff --git a/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
index b07ed0baa9..2fe358e079 100644
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -41,7 +41,7 @@ func TestLookupStaticHost(t *testing.T) {
 \t\tif len(ips) != len(tt.ips) {\n \t\t\tt.Errorf(\"# of hosts = %v; want %v\",\n \t\t\t\tlen(ips), len(tt.ips))\n-\t\t\treturn\n+\t\t\tcontinue\n \t\t}\n \t\tfor k, v := range ips {\n \t\t\tif tt.ips[k].String() != v {\n

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

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

元コミット内容

このコミットは、netパッケージのhosts_test.goファイル内のTestLookupStaticHost関数において、エラー発生時にhostsPathが適切に元の値に復元されない問題を修正します。元のコードでは、len(ips) != len(tt.ips)という条件が満たされた場合にreturnステートメントが実行され、その結果、テストのクリーンアップ処理がスキップされ、hostsPathが元の状態に戻らない可能性がありました。

変更の背景

TestLookupStaticHostテストは、静的なホストルックアップ(/etc/hostsファイルのようなもの)の動作を検証するためのものです。このテストでは、テストの実行中に一時的にhostsPathという内部変数を変更し、テスト終了後に元の値に戻す必要があります。

コミットメッセージによると、この問題はhttps://golang.org/cl/15960047/での議論に端を発しています。このリンクは、GoランタイムのTestStackGrowthテストにおける競合状態の修正に関するもので、直接今回のコミットの対象ではありませんが、テストにおけるリソースのクリーンアップの重要性や、エラーパスでのリソースリークの可能性について議論された文脈の一部であった可能性があります。

今回のコミットの具体的な背景は、TestLookupStaticHostが複数のテストケースをループで実行する際に、あるテストケースでエラーが発生してreturnしてしまうと、その後のテストケースの実行や、テスト全体が終了する際のhostsPathの復元が適切に行われないという問題です。これにより、テスト環境が汚染され、後続のテストやシステム全体の動作に予期せぬ影響を与える可能性がありました。

前提知識の解説

  • Go言語のnetパッケージ: Go言語の標準ライブラリの一部で、ネットワークI/O機能を提供します。TCP/UDP通信、DNSルックアップ、HTTPクライアント/サーバーなどが含まれます。
  • /etc/hostsファイル: Unix系システムにおけるホスト名とIPアドレスのマッピングを定義するファイルです。DNSルックアップよりも優先されることがあります。Goのnetパッケージは、このファイルの内容を読み取ってホスト名を解決する機能を持っています。
  • hostsPath: Goのnetパッケージ内部で、/etc/hostsファイルのようなホスト情報ファイルのパスを指すために使用される変数(またはそれに類する概念)であると推測されます。テストでは、このパスを一時的に変更して、特定のテストデータを持つファイルを参照させることがあります。
  • テストにおけるリソースのクリーンアップ: ソフトウェアテストでは、テストの実行中にファイル、ネットワーク接続、データベース接続などのリソースを一時的に作成または変更することがよくあります。テストが終了した後、これらのリソースを元の状態に戻したり、適切に解放したりする「クリーンアップ」処理は非常に重要です。クリーンアップが不十分だと、テスト環境が汚染され、テストの再現性が損なわれたり、他のテストに悪影響を与えたりする可能性があります。
  • deferステートメント: Go言語のdeferステートメントは、関数がリターンする直前に実行される関数呼び出しをスケジュールします。これは、リソースの解放やクリーンアップ処理を確実に行うための非常に便利な機能です。今回のコミットではdeferが直接使われているわけではありませんが、同様のリソースクリーンアップの文脈で理解すると良いでしょう。
  • return vs continue:
    • return: 現在の関数から即座に抜け出し、呼び出し元に制御を戻します。ループ内で使用された場合、ループ全体も終了します。
    • continue: 現在のループの残りの処理をスキップし、次のイテレーションに進みます。ループ自体は継続されます。

技術的詳細

TestLookupStaticHost関数は、複数のテストケース(tt)をループで処理しています。各テストケースでは、特定のホスト名に対するIPアドレスのルックアップを行い、その結果が期待通りであるかを検証します。

元のコードでは、ルックアップで得られたIPアドレスの数(len(ips))が期待されるIPアドレスの数(len(tt.ips))と異なる場合、t.Errorfでエラーを報告し、その後にreturnしていました。

// src/pkg/net/hosts_test.go (変更前)
if len(ips) != len(tt.ips) {
    t.Errorf("# of hosts = %v; want %v",
        len(ips), len(tt.ips))
    return // ここで関数が終了してしまう
}

このreturnが問題でした。TestLookupStaticHost関数は、テストの開始時にhostsPathを一時的な値に設定し、テストの終了時に元の値に戻すためのクリーンアップロジックを持っているはずです(通常はdeferステートメントや、関数の最後に実行される明示的なクリーンアップコード)。しかし、ループの途中でreturnしてしまうと、そのクリーンアップロジックが実行されず、hostsPathが変更されたままになってしまう可能性がありました。

このコミットでは、returncontinueに置き換えることでこの問題を解決しています。

// src/pkg/net/hosts_test.go (変更後)
if len(ips) != len(tt.ips) {
    t.Errorf("# of hosts = %v; want %v",
        len(ips), len(tt.ips))
    continue // 次のテストケースに進むが、関数は終了しない
}

continueを使用することで、現在のテストケースでエラーが発生しても、ループの次のイテレーションに進みます。これにより、TestLookupStaticHost関数自体は最後まで実行され、関数スコープのクリーンアップ処理(もしあれば)が確実に実行されるようになります。結果として、hostsPathが常に元の値に復元されることが保証され、テスト環境の汚染が防がれます。

この変更は、テストの堅牢性と信頼性を向上させるための重要な修正です。特に、テストが実行される環境の整合性を保つ上で不可欠です。

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

src/pkg/net/hosts_test.goファイルの以下の行が変更されました。

--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -41,7 +41,7 @@ func TestLookupStaticHost(t *testing.T) {
 \t\tif len(ips) != len(tt.ips) {\n \t\t\tt.Errorf(\"# of hosts = %v; want %v\",\n \t\t\t\tlen(ips), len(tt.ips))\n-\t\t\treturn\n+\t\t\tcontinue\n \t\t}\n \t\tfor k, v := range ips {\n \t\t\tif tt.ips[k].String() != v {\n

具体的には、44行目のreturncontinueに置き換えられています。

コアとなるコードの解説

変更された行は、TestLookupStaticHost関数内のテストケースを反復処理するループの中にあります。

// 変更前
if len(ips) != len(tt.ips) {
    t.Errorf("# of hosts = %v; want %v",
        len(ips), len(tt.ips))
    return // ここで関数全体が終了し、クリーンアップがスキップされる可能性があった
}

// 変更後
if len(ips) != len(tt.ips) {
    t.Errorf("# of hosts = %v; want %v",
        len(ips), len(tt.ips))
    continue // 現在のテストケースの残りをスキップし、次のテストケースに進む。関数は継続される。
}

この変更により、IPアドレスの数が期待値と一致しないというエラーが発生した場合でも、テスト関数全体が終了することなく、ループの次のイテレーション(次のテストケース)に進むようになります。これにより、テスト関数が最後まで実行され、テスト開始時に設定されたhostsPathの変更が、テスト終了時に確実に元の値に復元されることが保証されます。これは、テストの独立性と環境のクリーンさを保つ上で非常に重要です。

関連リンク

参考にした情報源リンク