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

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

このコミットは、Go言語の標準ライブラリ net パッケージ内の TestTCPStress テストの実行時間を短縮することを目的としています。特に、FreeBSD環境のビルドボットで発生していたテストのタイムアウト問題を解決するために、testing.Short() フラグを利用してテストのメッセージ数を削減する変更が加えられました。

コミット

commit f8ca13c3e5a85d6f9dbce499aca8006c104376ee
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Wed Aug 14 21:53:27 2013 +0400

    net: make TCPStress test shorter
    It timeouts on freebsd builders:
    http://build.golang.org/log/3d8169e13bff912bebf6fd3c54b34ad2d29a7221
    but there are always runnable goroutines,
    which suggests that it's slowly progressing.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/12939043

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

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

元コミット内容

net: make TCPStress test shorter
It timeouts on freebsd builders:
http://build.golang.org/log/3d8169e13bff912bebf6fd3c54b34ad2d29a7221
but there are always runnable goroutines,
which suggests that it's slowly progressing.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12939043

変更の背景

このコミットの主な背景は、Goプロジェクトの継続的インテグレーション(CI)システム、特にFreeBSD環境のビルドボットで発生していた TestTCPStress テストのタイムアウト問題です。コミットメッセージに記載されているログリンク(http://build.golang.org/log/3d8169e13bff912bebf6fd3c54b34ad2d29a7221)は、この問題が実際に発生していたことを示しています。

テストがタイムアウトする一方で、「常に実行可能なゴルーチンが存在する」という記述は、テスト自体がデッドロックしているわけではなく、単に処理に時間がかかりすぎていることを示唆しています。これは、テストが想定よりも多くのリソース(CPU時間、ネットワークI/Oなど)を消費しているか、特定の環境(この場合はFreeBSD)でパフォーマンスが低下している可能性を示しています。

CIシステムにおいてテストのタイムアウトは、ビルドの失敗や遅延を引き起こし、開発プロセスのボトルネックとなります。そのため、テストのロジックを変更せずに、実行時間を短縮する対策が必要とされました。Goの testing パッケージが提供する testing.Short() フラグは、このようなシナリオでテストの実行時間を調整するための標準的なメカニズムです。

前提知識の解説

Go言語の testing パッケージ

Go言語には、ユニットテストやベンチマークテストを記述するための組み込みの testing パッケージが用意されています。テストファイルは通常、テスト対象のソースファイルと同じディレクトリに _test.go というサフィックスを付けて配置されます。テスト関数は Test で始まり、*testing.T 型の引数を取ります。

testing.Short() フラグ

testing.Short() は、testing パッケージが提供する関数で、テストが「短い」モードで実行されているかどうかを示すブール値を返します。このモードは、go test -short コマンドライン引数を使用して有効にできます。

testing.Short() フラグの主な目的は、開発者がローカルでテストを実行する際に、時間のかかるテスト(例: ネットワークテスト、ファイルI/Oが多いテスト、大規模なデータセットを扱うテスト)をスキップまたは短縮できるようにすることです。これにより、開発サイクルを高速化し、CIシステムでの実行時間を最適化することができます。

テストコード内で if testing.Short() { ... } のように条件分岐を記述することで、短いモードの場合にテストの反復回数を減らしたり、一部のテストケースをスキップしたりするロジックを実装できます。

CI/CD環境におけるテストのタイムアウト

継続的インテグレーション(CI)および継続的デリバリー(CD)パイプラインでは、テストの実行時間は非常に重要です。テストが長すぎると、フィードバックループが長くなり、開発者の生産性が低下します。また、CIシステムには通常、個々のテストやビルド全体に対してタイムアウトが設定されています。このタイムアウトを超過すると、テストは強制終了され、ビルドは失敗とマークされます。

ネットワークテストやストレステストのように、実行に時間がかかる可能性のあるテストは、CI環境の安定性や効率性に影響を与えることがあります。このような場合、testing.Short() のようなメカニズムを利用して、CI環境ではテストの負荷を軽減し、ローカル開発環境ではより徹底的なテストを実行できるようにすることが一般的です。

Goの net パッケージとTCP通信

net パッケージは、Go言語でネットワークI/Oを扱うための主要なパッケージです。TCP/IP、UDP、Unixドメインソケットなど、さまざまなネットワークプロトコルをサポートしています。TestTCPStress は、この net パッケージのTCP通信機能のストレス耐性をテストするものであり、多数の接続とメッセージの送受信をシミュレートすることで、ネットワークスタックの堅牢性やパフォーマンスを検証します。

技術的詳細

このコミットの技術的な核心は、Goの testing.Short() フラグを利用して、TestTCPStress テストの実行ロジックを動的に変更することにあります。

元のコードでは、msgs(メッセージ数)が 1e4 (10,000) という定数で定義されていました。これは、テストが常に10,000個のメッセージを送受信しようとすることを意味します。FreeBSDのビルドボットでタイムアウトが発生した原因は、このメッセージ数が多すぎたため、特定の環境下でテストが完了するまでに許容された時間を超えてしまったことにあります。

変更後、msgs は定数ではなく変数として宣言され、その初期値は引き続き 1e4 となります。しかし、その直後に if testing.Short() { msgs = 1e2 } という条件分岐が追加されました。

この変更により、以下の挙動が実現されます。

  1. 通常実行時(go test: testing.Short()false を返すため、msgs の値は 1e4 (10,000) のままとなり、テストはフルスケールで実行されます。
  2. 短いモード実行時(go test -short: testing.Short()true を返すため、msgs の値は 1e2 (100) に上書きされます。これにより、テストが送受信するメッセージ数が100分の1に削減され、実行時間が大幅に短縮されます。

このアプローチは、テストの網羅性を損なうことなく、CI環境でのタイムアウト問題を回避するための効果的な手段です。開発者はローカルで完全なテストを実行し、CIシステムではより高速なサブセットのテストを実行することで、開発ワークフローの効率を向上させることができます。

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

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

--- a/src/pkg/net/tcp_test.go
+++ b/src/pkg/net/tcp_test.go
@@ -497,8 +497,11 @@ func TestTCPReadWriteMallocs(t *testing.T) {
 
 func TestTCPStress(t *testing.T) {
 	const conns = 2
-	const msgs = 1e4
 	const msgLen = 512
+	msgs := int(1e4)
+	if testing.Short() {
+		msgs = 1e2
+	}
 
 	sendMsg := func(c Conn, buf []byte) bool {
 		n, err := c.Write(buf)

コアとなるコードの解説

変更されたコードブロックは TestTCPStress 関数内にあります。

  1. const msgs = 1e4 の削除: 元のコードでは msgs が定数として定義されていました。定数はコンパイル時に値が決定され、実行時に変更することはできません。

  2. msgs := int(1e4) の追加: msgs が変数として再定義されました。1e4 は浮動小数点リテラルですが、int() で明示的に整数型にキャストされています。これにより、msgs は初期値として10,000を持ちますが、後で値を変更できるようになります。

  3. if testing.Short() { msgs = 1e2 } の追加: この行が変更の核心です。

    • testing.Short(): この関数は、go test -short コマンドでテストが実行された場合に true を返します。それ以外の場合は false を返します。
    • msgs = 1e2: testing.Short()true を返した場合、つまりテストが短いモードで実行されている場合、msgs の値は 1e2 (100) に上書きされます。

この変更により、TestTCPStress テストは、go test -short が指定された場合には100メッセージのみを処理し、それ以外の場合(通常の go test やCI環境でのフルテスト実行時)には10,000メッセージを処理するようになります。これにより、FreeBSDビルドボットでのタイムアウト問題が解決され、同時にテストの網羅性も維持されます。

関連リンク

参考にした情報源リンク

  • Go言語 testing パッケージ公式ドキュメント: https://pkg.go.dev/testing
  • testing.Short() の詳細に関する情報 (Goのドキュメントや関連するブログ記事など)
    • go help testflag コマンドの出力 (ローカル環境で go help testflag を実行すると -short フラグに関する説明が得られます)
    • Goのテストに関する一般的な情報源 (例: "Effective Go" の Testing セクションなど)
  • 継続的インテグレーション (CI) および継続的デリバリー (CD) の概念に関する一般的な情報源
  • TCP/IPプロトコルおよびネットワークプログラミングに関する一般的な情報源
  • FreeBSDオペレーティングシステムに関する一般的な情報源
  • GoプロジェクトのビルドシステムおよびCIインフラに関する一般的な情報源 (Goの公式ブログや開発者向けドキュメントなど)