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

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

src/cmd/go/test.go ファイルは、Go言語の標準コマンドラインツールである go コマンドの一部であり、特に go test サブコマンドの内部的なテスト実行ロジックを定義しています。このファイルは、Goのテストフレームワークがテストバイナリをどのように起動し、その実行を監視し、タイムアウトなどのメカニズムをどのように適用するかを管理する役割を担っています。

コミット

commit f2b51f564f2bf457c4dc77c88adb5d11b513d658
Author: Russ Cox <rsc@golang.org>
Date:   Wed Jan 11 12:44:31 2012 -0800

    cmd/go: change deadline to 10 minutes

    1 minute is not enough for the slower builders.

    R=adg
    CC=golang-dev
    https://golang.org/cl/5533068

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

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

元コミット内容

cmd/go: change deadline to 10 minutes

1 minute is not enough for the slower builders.

変更の背景

このコミットは、Go言語のテスト実行におけるデフォルトのタイムアウト時間を1分から10分に延長することを目的としています。元の1分というデッドラインは、Goプロジェクトの継続的インテグレーション(CI)システムで使用されている一部の「遅いビルダー」(テスト実行環境)にとって不十分であることが判明しました。

Goプロジェクトでは、様々なアーキテクチャ、オペレーティングシステム、ハードウェア構成を持つ多数のビルダーがテストを実行しています。これらのビルダーの中には、リソースが限られていたり、仮想環境で動作していたり、あるいは単に物理的に遠隔地に配置されているために、他のビルダーよりもテストの実行に時間がかかるものがあります。

テストが1分以内に完了しない場合、それはテストがハングしているか、無限ループに陥っているか、あるいは単に非常に時間がかかるテストである可能性があります。しかし、遅いビルダーの場合、正しく動作しているテストであっても、単に実行環境の制約により1分を超えてしまうことがありました。これにより、CIシステム上で不必要なテスト失敗やタイムアウトが発生し、開発プロセスの妨げとなっていました。

この問題を解決し、CIシステムの安定性を向上させるため、テストのデッドラインを10分に延長することが決定されました。これにより、遅いビルダーでも正当なテストがタイムアウトすることなく完了できるようになり、CIパイプラインの信頼性が向上しました。この変更は、Goプロジェクトのコードレビューシステム(Gerrit)で議論され、承認されました(LGTM by dsymonds)。

前提知識の解説

Go言語のテスト (go test)

Go言語には、標準で強力なテストフレームワークが組み込まれています。開発者は、_test.go というサフィックスを持つファイルにテストコードを記述し、go test コマンドを実行することで、簡単にテストを実行できます。go test は、指定されたパッケージ内のテスト関数を検出し、テストバイナリをコンパイルして実行し、その結果を報告します。

Goのビルドシステムとビルダー

Goプロジェクトは、世界中の様々なプラットフォームで動作するように設計されており、そのために広範な継続的インテグレーション(CI)システムを運用しています。このCIシステムは、多数の「ビルダー」と呼ばれる自動化された環境で構成されています。各ビルダーは特定のOS、アーキテクチャ、Goのバージョン、またはその他の構成でGoのコードをビルドし、テストを実行します。これにより、Go言語の変更が様々な環境で互換性を損なわないことを保証しています。

「遅いビルダー」とは、これらのビルダーの中で、何らかの理由(例: 低速なCPU、少ないメモリ、ネットワーク遅延、仮想化オーバーヘッドなど)により、他のビルダーよりもタスクの完了に時間がかかるものを指します。

デッドライン(タイムアウト)の概念

ソフトウェア開発において、デッドラインまたはタイムアウトは、特定の操作が完了するまでに許容される最大時間を指します。これは、プログラムが無限ループに陥ったり、外部リソース(ネットワーク、データベースなど)からの応答を永久に待ち続けたりするのを防ぐために非常に重要です。テスト実行の文脈では、デッドラインは、テストが一定時間内に完了しない場合に、そのテストを強制的に終了させるメカニズムとして機能します。これにより、CIシステムがハングしたテストによってブロックされるのを防ぎ、リソースを解放し、次のテストやビルドに進むことができます。

Goの標準ライブラリにおける時間管理

Go言語の標準ライブラリには、時間(timeパッケージ)を扱うための豊富な機能が用意されています。

  • time.Duration: 時間の長さを表す型で、time.Secondtime.Minute のような定数を使って時間を指定できます。
  • time.NewTimer(d Duration): 指定された期間 d が経過した後に、チャネルに現在の時刻を送信する Timer を作成します。これは、タイムアウト処理を実装する際によく使用されます。タイマーが発火すると、関連するチャネルに値が送信され、プログラムはそのイベントを検出して適切なアクション(例: テストの強制終了)を実行できます。

技術的詳細

この変更は、src/cmd/go/test.go ファイル内の runTest 関数に影響を与えます。runTest 関数は、go test コマンドが個々のテストバイナリを実行する際の主要なロジックを含んでいます。

  1. テストバイナリの起動: runTest 関数内で、cmd.Start() が呼び出されます。これは、コンパイルされたテストバイナリを新しいプロセスとして起動する役割を担います。
  2. デッドラインの設定: テストバイナリが起動されると、その実行を監視するためのデッドラインが設定されます。このデッドラインは、テストが予期せずハングした場合に、そのプロセスを強制的に終了させるための「最後の手段」として機能します。これは、特にCIビルダーの安定性を保つ上で重要です。ハングしたテストがリソースを占有し続けることを防ぎ、ビルダーが次のタスクに進めるようにします。
  3. time.NewTimer の利用: デッドラインは time.NewTimer(deadline) を使用して実装されています。これにより、指定された時間が経過するとイベントが発生するタイマーが設定されます。runTest 関数は、このタイマーからのイベント、またはテストバイナリの正常終了のいずれかを待機します。タイマーが先に発火した場合、テストはタイムアウトと見なされ、強制終了されます。
  4. コメントの追加: 変更されたコードには、デッドラインの目的を明確にするためのコメントが追加されています。このコメントは、「これは、ハングしたテストバイナリを検出し、停止させるための最後の手段のデッドラインであり、ビルダーを稼働させ続けるためである」と説明しています。これにより、このデッドラインが単なる実行時間の制限ではなく、CIシステムの健全性を維持するための重要なメカニズムであることが強調されています。

この変更は、Goのテスト実行の堅牢性を高め、特にリソースが限られた環境でのCIパイプラインの信頼性を向上させる上で重要な役割を果たします。

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

--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -469,7 +469,12 @@ func (b *builder) runTest(a *action) error {

 	t0 := time.Now()
 	err := cmd.Start()
-	const deadline = 1 * time.Minute
+
+	// This is a last-ditch deadline to detect and
+	// stop wedged test binaries, to keep the builders
+	// running.
+	const deadline = 10 * time.Minute
+
 	tick := time.NewTimer(deadline)
 	if err == nil {
 		done := make(chan error)

コアとなるコードの解説

このコミットにおけるコアとなる変更は、src/cmd/go/test.go ファイル内の runTest 関数における deadline 定数の定義です。

変更前は、deadline 定数は以下のように定義されていました。

const deadline = 1 * time.Minute

これは、テスト実行のタイムアウトを1分に設定していました。

変更後、この行は以下のように修正されました。

	// This is a last-ditch deadline to detect and
	// stop wedged test binaries, to keep the builders
	// running.
	const deadline = 10 * time.Minute

この変更により、deadline の値が 1 * time.Minute から 10 * time.Minute に変更されました。これにより、テストバイナリが完了するまでに許容される最大時間が1分から10分に延長されました。

また、この変更には、デッドラインの目的を説明する新しいコメントが追加されています。このコメントは、このデッドラインが「ハングしたテストバイナリを検出し、停止させるための最後の手段」であり、「ビルダーを稼働させ続けるため」のものであることを明確にしています。これは、このタイムアウトが単にテストの実行時間を制限するだけでなく、GoのCIインフラストラクチャの安定性と効率性を維持するための重要なメカニズムであることを示唆しています。

このシンプルな定数の変更が、Goのテスト実行の堅牢性と、特にリソースが限られた環境でのCIパイプラインの信頼性に大きな影響を与えています。

関連リンク

参考にした情報源リンク

  • Go Gerrit Change: https://golang.org/cl/5533068
  • Go言語の公式ドキュメント(go test コマンド、time パッケージに関する情報)
  • Goプロジェクトの継続的インテグレーションに関する一般的な知識