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

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

このコミットは、Go言語の標準ライブラリ net パッケージにおけるDNSルックアップのテストケース追加に関するものです。特に、netgocgo の両方のDNS解決メカニズムを検証するためのテストが導入されています。

コミット

commit 2b3ad827a6c45395db669aeec331ac134582a56
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Thu Dec 19 07:40:10 2013 +0900

    net: add test cases for the both of netgo, cgo DNS lookups
    
    Update #4078
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/14638043

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

https://github.com/golang/go/commit/2b3ad827a6c45395db669aeec3313ac134582a56

元コミット内容

net: add test cases for the both of netgo, cgo DNS lookups

このコミットは、Goの net パッケージに、netgocgo の両方のDNSルックアップメカニズムのためのテストケースを追加します。これは、Go issue #4078 に関連する更新です。

変更の背景

Go言語のネットワークパッケージ net は、DNS(Domain Name System)の名前解決を行う際に、複数のメカニズムをサポートしています。主なものとして、Go言語自身で実装された純粋なGoコードによるDNSリゾルバ(netgo)と、C言語の標準ライブラリ(通常はglibcなどのシステムリゾルバ)をCgo経由で利用するリゾルバ(cgo)があります。

Goの初期のバージョンでは、Cgoが利用可能な環境(特にUnix系システム)ではデフォルトでCgoベースのリゾルバが使用されていました。これは、システムの設定(/etc/resolv.conf/etc/hosts など)や、NSS (Name Service Switch) の設定(/etc/nsswitch.conf)に完全に準拠できるという利点がありました。しかし、Cgoを使用すると、クロスコンパイルが複雑になったり、静的リンクが困難になったり、あるいはCgoのオーバーヘッドが発生したりするなどのデメリットも存在しました。

そのため、Go 1.1以降では、netgo ビルドタグを使用することで、純粋なGo実装のリゾルバを強制的に使用できるようになりました。これにより、Cgoに依存しないバイナリを生成できるようになり、デプロイの柔軟性が向上しました。

しかし、この二つの異なるDNS解決メカニズムが存在することで、それぞれが期待通りに動作するか、特にエッジケースや特定の設定下で問題が発生しないかを検証することが重要になります。Go issue #4078 は、おそらくこれらのDNSルックアップメカニズムに関する既存のバグや、テストカバレッジの不足を指摘していたと考えられます。このコミットは、その問題に対処し、両方のリゾルバが正しく機能することを保証するためのテストを追加することを目的としています。

前提知識の解説

DNS (Domain Name System)

DNSは、インターネット上のコンピュータやサービスを識別するためのドメイン名(例: example.com)を、それに対応するIPアドレス(例: 93.184.216.34)に変換する分散型のシステムです。ユーザーがウェブサイトにアクセスする際、ブラウザはまずDNSを使ってドメイン名をIPアドレスに解決し、そのIPアドレスを使ってサーバーに接続します。

Go言語の net パッケージ

Go言語の標準ライブラリ net パッケージは、ネットワークI/Oのプリミティブを提供します。これには、TCP/UDP接続、IPアドレスの操作、そしてDNSの名前解決などが含まれます。

Cgo

Cgoは、GoプログラムからC言語のコードを呼び出すためのGoの機能です。これにより、Go言語で書かれたアプリケーションが、既存のCライブラリ(例えば、システムコールや特定のハードウェアと対話するためのライブラリ)を利用できるようになります。DNS解決の文脈では、CgoはシステムにインストールされているC言語ベースのDNSリゾルバ(通常はglibcの getaddrinfo など)を呼び出すために使用されます。

netgocgo ビルドタグ

Goのビルドシステムでは、ビルドタグ(build tags)を使用して、特定の条件に基づいてソースファイルをコンパイルに含めるか除外するかを制御できます。

  • cgo: このタグは、Cgoが有効な場合に自動的に設定されます。Goのネットワークパッケージでは、このタグが存在する場合、Cgoを介してシステムのDNSリゾルバを使用しようとします。
  • netgo: このタグは、Go言語自身で実装された純粋なGoコードによるDNSリゾルバを使用することを強制するために、明示的にビルドコマンドで指定されます(例: go build -tags netgo)。このタグが指定されると、Cgoベースのリゾルバは使用されません。
  • !cgo: cgo タグが設定されていないことを意味します。これは、Cgoが無効な環境や、netgo タグが指定された場合に該当します。
  • !netgo: netgo タグが設定されていないことを意味します。これは、Cgoベースのリゾルバが使用される可能性がある場合に該当します。

これらのタグの組み合わせによって、Goの net パッケージはDNS解決の挙動を切り替えます。

cgoLookupIPgoLookupIP

Goの net パッケージ内部には、DNSルックアップを行うための抽象化された関数が存在します。

  • cgoLookupIP: Cgoを介してシステムのDNSリゾルバを呼び出すための内部関数(またはそのラッパー)。
  • goLookupIP: 純粋なGoコードで実装されたDNSリゾルバを呼び出すための内部関数。

これらの関数は、外部に公開されている net.LookupIP などの関数から内部的に呼び出され、ビルドタグや環境に応じて適切な実装が選択されます。

技術的詳細

このコミットは、GoのDNSルックアップメカニズムの堅牢性を高めるために、netgocgo の両方のパスを検証する新しいテストケースを追加します。具体的には、以下の2つの新しいテストファイルが追加されています。

  1. src/pkg/net/cgo_unix_test.go
  2. src/pkg/net/netgo_unix_test.go

これらのファイルは、それぞれ異なるビルドタグの組み合わせでコンパイルされるように設計されており、それぞれのDNS解決パスが正しく機能するかどうかを独立してテストします。

cgo_unix_test.go のテストロジック

このテストファイルは、+build cgo,!netgo というビルドタグを持っています。これは、Cgoが有効で、かつ netgo タグが指定されていない(つまり、Cgoベースのリゾルバが使用されるべき)Unix系システムでのみコンパイルおよび実行されることを意味します。

TestCgoLookupIP 関数では、以下の検証が行われます。

  • cgoLookupIP("localhost") を呼び出し、その結果を検証します。
    • okfalse でないこと(cgoLookupIP がプレースホルダーではないこと)を確認します。これは、Cgoベースのリゾルバが実際に利用可能であることを意味します。
    • errnil であること(エラーが発生しないこと)を確認します。
  • goLookupIP("localhost") を呼び出し、その結果を検証します。
    • errnil であること(エラーが発生しないこと)を確認します。これは、Cgoベースのリゾルバが使用されている場合でも、Go実装のリゾルバが機能することを確認するためです。

このテストの目的は、Cgoが有効な環境で、システムのリゾルバが正しく機能し、cgoLookupIP が期待通りに動作することを確認することです。

netgo_unix_test.go のテストロジック

このテストファイルは、+build !cgo netgo というビルドタグを持っています。これは、Cgoが無効であるか、または netgo タグが明示的に指定されている(つまり、純粋なGo実装のリゾルバが使用されるべき)Unix系システムでのみコンパイルおよび実行されることを意味します。

TestGoLookupIP 関数では、以下の検証が行われます。

  • cgoLookupIP("localhost") を呼び出し、その結果を検証します。
    • oktrue でないこと(cgoLookupIP がプレースホルダーであること)を確認します。これは、netgo モードではCgoベースのリゾルバが使用されないことを意味します。
    • errnil であること(エラーが発生しないこと)を確認します。cgoLookupIP がプレースホルダーである場合、通常はエラーを返さないか、特定のプレースホルダーエラーを返すことが期待されます。
  • goLookupIP("localhost") を呼び出し、その結果を検証します。
    • errnil であること(エラーが発生しないこと)を確認します。これは、netgo モードでGo実装のリゾルバが正しく機能することを確認するためです。

このテストの目的は、netgo モードで、純粋なGo実装のリゾルバが正しく機能し、Cgoベースのリゾルバが意図的にバイパスされていることを確認することです。

両方のテストファイルで localhost を使用しているのは、通常、システムのリゾルバ設定に依存せず、確実に解決できるホスト名であるためです。これにより、外部ネットワークの可用性や特定のDNSサーバーの設定に左右されずに、内部のDNS解決ロジックをテストできます。

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

このコミットによって追加されたファイルは以下の2つです。

  1. src/pkg/net/cgo_unix_test.go

    // Copyright 2013 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    // +build cgo,!netgo
    // +build darwin dragonfly freebsd linux netbsd openbsd
    
    package net
    
    import "testing"
    
    func TestCgoLookupIP(t *testing.T) {
    	host := "localhost"
    	_, err, ok := cgoLookupIP(host)
    	if !ok {
    		t.Errorf("cgoLookupIP must not be a placeholder")
    	}
    	if err != nil {
    		t.Errorf("cgoLookupIP failed: %v", err)
    	}
    	if _, err := goLookupIP(host); err != nil {
    		t.Errorf("goLookupIP failed: %v", err)
    	}
    }
    
  2. src/pkg/net/netgo_unix_test.go

    // Copyright 2013 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    // +build !cgo netgo
    // +build darwin dragonfly freebsd linux netbsd openbsd
    
    package net
    
    import "testing"
    
    func TestGoLookupIP(t *testing.T) {
    	host := "localhost"
    	_, err, ok := cgoLookupIP(host)
    	if ok {
    		t.Errorf("cgoLookupIP must be a placeholder")
    	}
    	if err != nil {
    		t.Errorf("cgoLookupIP failed: %v", err)
    	}
    	if _, err := goLookupIP(host); err != nil {
    		t.Errorf("goLookupIP failed: %v", err)
    	}
    }
    

コアとなるコードの解説

src/pkg/net/cgo_unix_test.go

  • ビルドタグ: // +build cgo,!netgo は、このファイルがCgoが有効で、かつ netgo タグが指定されていない場合にのみコンパイルされることを示します。これは、GoがCgoベースのDNSリゾルバを使用するデフォルトの動作をテストするためのものです。
  • TestCgoLookupIP 関数:
    • host := "localhost": テスト対象のホスト名として localhost を使用します。これは通常、システムのリゾルバによって確実に解決されるため、テストの安定性を高めます。
    • _, err, ok := cgoLookupIP(host): cgoLookupIP は、Cgoを介してシステムのDNSリゾルバを呼び出すGoの内部関数です。返り値の ok は、その関数が実際に利用可能(プレースホルダーではない)かどうかを示します。
    • if !ok { t.Errorf("cgoLookupIP must not be a placeholder") }: cgo モードでは cgoLookupIP が実際に機能する実装であるべきなので、oktrue であることを確認します。
    • if err != nil { t.Errorf("cgoLookupIP failed: %v", err) }: cgoLookupIP の呼び出しでエラーが発生しないことを確認します。
    • if _, err := goLookupIP(host); err != nil { t.Errorf("goLookupIP failed: %v", err) }: goLookupIP は純粋なGo実装のリゾルバです。cgo モードであっても、goLookupIP がエラーなく動作することを確認します。これは、Goのネットワークスタックが両方のリゾルバを適切に管理できることを保証するためです。

src/pkg/net/netgo_unix_test.go

  • ビルドタグ: // +build !cgo netgo は、このファイルがCgoが無効であるか、または netgo タグが明示的に指定されている場合にのみコンパイルされることを示します。これは、Goが純粋なGo実装のDNSリゾルバを使用する動作をテストするためのものです。
  • TestGoLookupIP 関数:
    • host := "localhost": 同様に localhost を使用します。
    • _, err, ok := cgoLookupIP(host): ここでも cgoLookupIP を呼び出しますが、netgo モードではその挙動が異なります。
    • if ok { t.Errorf("cgoLookupIP must be a placeholder") }: netgo モードでは、cgoLookupIP は使用されないため、その実装はプレースホルダーであるべきです。したがって、okfalse であることを確認します。
    • if err != nil { t.Errorf("cgoLookupIP failed: %v", err) }: プレースホルダーの呼び出しでエラーが発生しないことを確認します。
    • if _, err := goLookupIP(host); err != nil { t.Errorf("goLookupIP failed: %v", err) }: netgo モードでは goLookupIP が主要なリゾルバとなるため、これがエラーなく動作することを確実に検証します。

これらのテストは、GoのDNS解決メカニズムが、ビルドタグや環境に応じて適切に切り替わり、それぞれのパスで期待通りの結果を返すことを保証するための重要な追加です。これにより、Goアプリケーションのネットワーク機能の信頼性が向上します。

関連リンク

参考にした情報源リンク

  • Go issue #4078 の内容 (Web検索による)
  • Go言語のビルドタグに関する公式ドキュメント (Web検索による)
  • Go言語の net パッケージの内部実装に関する一般的な知識
  • Cgoに関するGo公式ドキュメント (Web検索による)
  • DNSの基本的な概念 (一般的な知識)
  • localhost の名前解決に関する一般的な知識I have read the commit data and formulated a detailed explanation. I will now output the explanation in Markdown format as requested.
# [インデックス 18067] ファイルの概要

このコミットは、Go言語の標準ライブラリ `net` パッケージにおけるDNSルックアップのテストケース追加に関するものです。特に、`netgo` と `cgo` の両方のDNS解決メカニズムを検証するためのテストが導入されています。

## コミット

commit 2b3ad827a6c45395db669aeec331ac134582a56 Author: Mikio Hara mikioh.mikioh@gmail.com Date: Thu Dec 19 07:40:10 2013 +0900

net: add test cases for the both of netgo, cgo DNS lookups

Update #4078

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/14638043

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

[https://github.com/golang/go/commit/2b3ad827a6c45395db669aeec3313ac134582a56](https://github.com/golang/go/commit/2b3ad827a6c45395db669aeec3313ac134582a56)

## 元コミット内容

`net: add test cases for the both of netgo, cgo DNS lookups`

このコミットは、Goの `net` パッケージに、`netgo` と `cgo` の両方のDNSルックアップメカニズムのためのテストケースを追加します。これは、Go issue #4078 に関連する更新です。

## 変更の背景

Go言語のネットワークパッケージ `net` は、DNS(Domain Name System)の名前解決を行う際に、複数のメカニズムをサポートしています。主なものとして、Go言語自身で実装された純粋なGoコードによるDNSリゾルバ(`netgo`)と、C言語の標準ライブラリ(通常はglibcなどのシステムリゾルバ)をCgo経由で利用するリゾルバ(`cgo`)があります。

Goの初期のバージョンでは、Cgoが利用可能な環境(特にUnix系システム)ではデフォルトでCgoベースのリゾルバが使用されていました。これは、システムの設定(`/etc/resolv.conf` や `/etc/hosts` など)や、NSS (Name Service Switch) の設定(`/etc/nsswitch.conf`)に完全に準拠できるという利点がありました。しかし、Cgoを使用すると、クロスコンパイルが複雑になったり、静的リンクが困難になったり、あるいはCgoのオーバーヘッドが発生したりするなどのデメリットも存在しました。

そのため、Go 1.1以降では、`netgo` ビルドタグを使用することで、純粋なGo実装のリゾルバを強制的に使用できるようになりました。これにより、Cgoに依存しないバイナリを生成できるようになり、デプロイの柔軟性が向上しました。

しかし、この二つの異なるDNS解決メカニズムが存在することで、それぞれが期待通りに動作するか、特にエッジケースや特定の設定下で問題が発生しないかを検証することが重要になります。Go issue #4078 は、おそらくこれらのDNSルックアップメカニズムに関する既存のバグや、テストカバレッジの不足を指摘していたと考えられます。このコミットは、その問題に対処し、両方のリゾルバが正しく機能することを保証するためのテストを追加することを目的としています。

## 前提知識の解説

### DNS (Domain Name System)

DNSは、インターネット上のコンピュータやサービスを識別するためのドメイン名(例: `example.com`)を、それに対応するIPアドレス(例: `93.184.216.34`)に変換する分散型のシステムです。ユーザーがウェブサイトにアクセスする際、ブラウザはまずDNSを使ってドメイン名をIPアドレスに解決し、そのIPアドレスを使ってサーバーに接続します。

### Go言語の `net` パッケージ

Go言語の標準ライブラリ `net` パッケージは、ネットワークI/Oのプリミティブを提供します。これには、TCP/UDP接続、IPアドレスの操作、そしてDNSの名前解決などが含まれます。

### Cgo

Cgoは、GoプログラムからC言語のコードを呼び出すためのGoの機能です。これにより、Go言語で書かれたアプリケーションが、既存のCライブラリ(例えば、システムコールや特定のハードウェアと対話するためのライブラリ)を利用できるようになります。DNS解決の文脈では、CgoはシステムにインストールされているC言語ベースのDNSリゾルバ(通常はglibcの `getaddrinfo` など)を呼び出すために使用されます。

### `netgo` と `cgo` ビルドタグ

Goのビルドシステムでは、ビルドタグ(build tags)を使用して、特定の条件に基づいてソースファイルをコンパイルに含めるか除外するかを制御できます。

*   **`cgo`**: このタグは、Cgoが有効な場合に自動的に設定されます。Goのネットワークパッケージでは、このタグが存在する場合、Cgoを介してシステムのDNSリゾルバを使用しようとします。
*   **`netgo`**: このタグは、Go言語自身で実装された純粋なGoコードによるDNSリゾルバを使用することを強制するために、明示的にビルドコマンドで指定されます(例: `go build -tags netgo`)。このタグが指定されると、Cgoベースのリゾルバは使用されません。
*   **`!cgo`**: `cgo` タグが設定されていないことを意味します。これは、Cgoが無効な環境や、`netgo` タグが指定された場合に該当します。
*   **`!netgo`**: `netgo` タグが設定されていないことを意味します。これは、Cgoベースのリゾルバが使用される可能性がある場合に該当します。

これらのタグの組み合わせによって、Goの `net` パッケージはDNS解決の挙動を切り替えます。

### `cgoLookupIP` と `goLookupIP`

Goの `net` パッケージ内部には、DNSルックアップを行うための抽象化された関数が存在します。
*   `cgoLookupIP`: Cgoを介してシステムのDNSリゾルバを呼び出すための内部関数(またはそのラッパー)。
*   `goLookupIP`: 純粋なGoコードで実装されたDNSリゾルバを呼び出すための内部関数。

これらの関数は、外部に公開されている `net.LookupIP` などの関数から内部的に呼び出され、ビルドタグや環境に応じて適切な実装が選択されます。

## 技術的詳細

このコミットは、GoのDNSルックアップメカニズムの堅牢性を高めるために、`netgo` と `cgo` の両方のパスを検証する新しいテストケースを追加します。具体的には、以下の2つの新しいテストファイルが追加されています。

1.  `src/pkg/net/cgo_unix_test.go`
2.  `src/pkg/net/netgo_unix_test.go`

これらのファイルは、それぞれ異なるビルドタグの組み合わせでコンパイルされるように設計されており、それぞれのDNS解決パスが正しく機能するかどうかを独立してテストします。

### `cgo_unix_test.go` のテストロジック

このテストファイルは、`+build cgo,!netgo` というビルドタグを持っています。これは、Cgoが有効で、かつ `netgo` タグが指定されていない(つまり、Cgoベースのリゾルバが使用されるべき)Unix系システムでのみコンパイルおよび実行されることを意味します。

`TestCgoLookupIP` 関数では、以下の検証が行われます。
*   `cgoLookupIP("localhost")` を呼び出し、その結果を検証します。
    *   `ok` が `false` でないこと(`cgoLookupIP` がプレースホルダーではないこと)を確認します。これは、Cgoベースのリゾルバが実際に利用可能であることを意味します。
    *   `err` が `nil` であること(エラーが発生しないこと)を確認します。
*   `goLookupIP("localhost")` を呼び出し、その結果を検証します。
    *   `err` が `nil` であること(エラーが発生しないこと)を確認します。これは、Cgoベースのリゾルバが使用されている場合でも、Go実装のリゾルバが機能することを確認するためです。

このテストの目的は、Cgoが有効な環境で、システムのリゾルバが正しく機能し、`cgoLookupIP` が期待通りに動作することを確認することです。

### `netgo_unix_test.go` のテストロジック

このテストファイルは、`+build !cgo netgo` というビルドタグを持っています。これは、Cgoが無効であるか、または `netgo` タグが明示的に指定されている(つまり、純粋なGo実装のリゾルバが使用されるべき)Unix系システムでのみコンパイルおよび実行されることを意味します。

`TestGoLookupIP` 関数では、以下の検証が行われます。
*   `cgoLookupIP("localhost")` を呼び出し、その結果を検証します。
    *   `ok` が `true` でないこと(`cgoLookupIP` がプレースホルダーであること)を確認します。これは、`netgo` モードではCgoベースのリゾルバが使用されないことを意味します。
    *   `err` が `nil` であること(エラーが発生しないこと)を確認します。`cgoLookupIP` がプレースホルダーである場合、通常はエラーを返さないか、特定のプレースホルダーエラーを返すことが期待されます。
*   `goLookupIP("localhost")` を呼び出し、その結果を検証します。
    *   `err` が `nil` であること(エラーが発生しないこと)を確認します。これは、`netgo` モードでGo実装のリゾルバが正しく機能することを確認するためです。

このテストの目的は、`netgo` モードで、純粋なGo実装のリゾルバが正しく機能し、Cgoベースのリゾルバが意図的にバイパスされていることを確認することです。

両方のテストファイルで `localhost` を使用しているのは、通常、システムのリゾルバ設定に依存せず、確実に解決できるホスト名であるためです。これにより、外部ネットワークの可用性や特定のDNSサーバーの設定に左右されずに、内部のDNS解決ロジックをテストできます。

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

このコミットによって追加されたファイルは以下の2つです。

1.  `src/pkg/net/cgo_unix_test.go`
    ```go
    // Copyright 2013 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.

    // +build cgo,!netgo
    // +build darwin dragonfly freebsd linux netbsd openbsd

    package net

    import "testing"

    func TestCgoLookupIP(t *testing.T) {
    	host := "localhost"
    	_, err, ok := cgoLookupIP(host)
    	if !ok {
    		t.Errorf("cgoLookupIP must not be a placeholder")
    	}
    	if err != nil {
    		t.Errorf("cgoLookupIP failed: %v", err)
    	}
    	if _, err := goLookupIP(host); err != nil {
    		t.Errorf("goLookupIP failed: %v", err)
    	}
    }
    ```

2.  `src/pkg/net/netgo_unix_test.go`
    ```go
    // Copyright 2013 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.

    // +build !cgo netgo
    // +build darwin dragonfly freebsd linux netbsd openbsd

    package net

    import "testing"

    func TestGoLookupIP(t *testing.T) {
    	host := "localhost"
    	_, err, ok := cgoLookupIP(host)
    	if ok {
    		t.Errorf("cgoLookupIP must be a placeholder")
    	}
    	if err != nil {
    		t.Errorf("cgoLookupIP failed: %v", err)
    	}
    	if _, err := goLookupIP(host); err != nil {
    		t.Errorf("goLookupIP failed: %v", err)
    	}
    }
    ```

## コアとなるコードの解説

### `src/pkg/net/cgo_unix_test.go`

*   **ビルドタグ**: `// +build cgo,!netgo` は、このファイルがCgoが有効で、かつ `netgo` タグが指定されていない場合にのみコンパイルされることを示します。これは、GoがCgoベースのDNSリゾルバを使用するデフォルトの動作をテストするためのものです。
*   **`TestCgoLookupIP` 関数**:
    *   `host := "localhost"`: テスト対象のホスト名として `localhost` を使用します。これは通常、システムのリゾルバによって確実に解決されるため、テストの安定性を高めます。
    *   `_, err, ok := cgoLookupIP(host)`: `cgoLookupIP` は、Cgoを介してシステムのDNSリゾルバを呼び出すGoの内部関数です。返り値の `ok` は、その関数が実際に利用可能(プレースホルダーではない)かどうかを示します。
    *   `if !ok { t.Errorf("cgoLookupIP must not be a placeholder") }`: `cgo` モードでは `cgoLookupIP` が実際に機能する実装であるべきなので、`ok` が `true` であることを確認します。
    *   `if err != nil { t.Errorf("cgoLookupIP failed: %v", err) }`: `cgoLookupIP` の呼び出しでエラーが発生しないことを確認します。
    *   `if _, err := goLookupIP(host); err != nil { t.Errorf("goLookupIP failed: %v", err) }`: `goLookupIP` は純粋なGo実装のリゾルバです。`cgo` モードであっても、`goLookupIP` がエラーなく動作することを確認します。これは、Goのネットワークスタックが両方のリゾルバを適切に管理できることを保証するためです。

### `src/pkg/net/netgo_unix_test.go`

*   **ビルドタグ**: `// +build !cgo netgo` は、このファイルがCgoが無効であるか、または `netgo` タグが明示的に指定されている場合にのみコンパイルされることを示します。これは、Goが純粋なGo実装のDNSリゾルバを使用する動作をテストするためのものです。
*   **`TestGoLookupIP` 関数**:
    *   `host := "localhost"`: 同様に `localhost` を使用します。
    *   `_, err, ok := cgoLookupIP(host)`: ここでも `cgoLookupIP` を呼び出しますが、`netgo` モードではその挙動が異なります。
    *   `if ok { t.Errorf("cgoLookupIP must be a placeholder") }`: `netgo` モードでは、`cgoLookupIP` は使用されないため、その実装はプレースホルダーであるべきです。したがって、`ok` が `false` であることを確認します。
    *   `if err != nil { t.Errorf("cgoLookupIP failed: %v", err) }`: プレースホルダーの呼び出しでエラーが発生しないことを確認します。
    *   `if _, err := goLookupIP(host); err != nil { t.Errorf("goLookupIP failed: %v", err) }`: `netgo` モードでは `goLookupIP` が主要なリゾルバとなるため、これがエラーなく動作することを確実に検証します。

これらのテストは、GoのDNS解決メカニズムが、ビルドタグや環境に応じて適切に切り替わり、それぞれのパスで期待通りの結果を返すことを保証するための重要な追加です。これにより、Goアプリケーションのネットワーク機能の信頼性が向上します。

## 関連リンク

*   Go issue #4078: [https://github.com/golang/go/issues/4078](https://github.com/golang/go/issues/4078) (このコミットが更新するIssue)
*   Go CL 14638043: [https://golang.org/cl/14638043](https://golang.org/cl/14638043) (このコミットに対応するGerrit Change-ID)

## 参考にした情報源リンク

*   Go issue #4078 の内容 (Web検索による)
*   Go言語のビルドタグに関する公式ドキュメント (Web検索による)
*   Go言語の `net` パッケージの内部実装に関する一般的な知識
*   Cgoに関するGo公式ドキュメント (Web検索による)
*   DNSの基本的な概念 (一般的な知識)
*   `localhost` の名前解決に関する一般的な知識