百科事典をテストする

問題を報告する ソースを表示 Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

テスト実行環境の完全な仕様。

背景

Bazel BUILD 言語には、多くの言語で自動テスト プログラムを定義するために使用できるルールが含まれています。

テストは bazel test を使用して実行されます。

ユーザーはテストバイナリを直接実行することもできます。このような呼び出しは以下の要件に準拠しないため、許可はされますが推奨されません。

テストは 密閉型である必要があります。つまり、宣言された依存関係があるリソースにのみアクセスする必要があります。テストが適切に密閉されていない場合、過去に再現可能な結果は得られません。これは、犯人探し(どの変更がテストを壊したかを特定すること)、リリース エンジニアリングの監査可能性、テストのリソース分離(一部のテストがサーバーと通信しているという理由で、自動テスト フレームワークがサーバーに DDOS 攻撃を仕掛けるべきではない)にとって重大な問題となる可能性があります。

目標

このページの目的は、Bazel テストのランタイム環境と想定される動作を正式に確立することです。また、テストランナーとビルドシステムにも要件が課されます。

テスト環境の仕様は、テスト作成者が未指定の動作に依存することを回避するのに役立ちます。これにより、テスト インフラストラクチャは実装の変更をより自由に行うことができます。この仕様により、現在多くのテストが合格しているにもかかわらず、適切に密閉性、決定性、再入可能性が確保されていない状態を解消します。

このページは、規範的かつ権威的であることを目的としています。この仕様とテストランナーの実装された動作が一致しない場合、仕様が優先されます。

提案された仕様

キーワード「しなければならない」、「してはならない」、「要求される」、「するものとする」、「しないものとする」、「すべきである」、「すべきではない」、「推奨される」、「しても構わない」、「任意」は、IETF RFC 2119 に記載されているように解釈されます。

テストの目的

Bazel テストの目的は、リポジトリにチェックインされたソースファイルのプロパティを確認することです。(このページでは、「ソースファイル」にはテストデータ、ゴールデン出力、バージョン管理下にあるその他のすべてのものが含まれます)。あるユーザーが、維持されることを想定した不変条件をアサートするテストを作成します。他のユーザーは後でテストを実行して、不変条件が破られていないかどうかを確認します。テストがソースファイル以外の変数に依存している場合(非密閉型)、テストの価値は低下します。テストが合格しなくなったときに、後続のユーザーは自分の変更が原因であるかどうかを確信できないためです。

したがって、テストの結果は次のもののみに依存する必要があります。

  • テストが依存関係を宣言しているソースファイル
  • テストが依存関係を宣言しているビルドシステムのプロダクト
  • テストランナーによって動作が一定に保たれることが保証されているリソース

現在、このような動作は強制されていません。ただし、テストランナーは今後このような強制を追加する権利を有します。

ビルドシステムの役割

テストルールは、それぞれが実行可能プログラムを生成する必要があるという点で、バイナリルールに似ています。一部の言語では、これは言語固有のハーネスとテストコードを組み合わせたスタブ プログラムです。テストルールは他の出力も生成する必要があります。テストランナーには、メインのテスト実行可能ファイルに加えて、runfilesのマニフェスト、実行時にテストで使用可能にする必要がある入力ファイルが必要です。また、テストのタイプ、サイズ、タグに関する情報が必要になることもあります。

ビルドシステムは、ランファイルを使用してコードとデータを配信できます。(これは、動的リンクの使用などにより、テスト間でファイルを共有して各テスト バイナリを小さくする最適化として使用されることがあります)。ビルドシステムは、生成された実行可能ファイルが、ソースツリーまたは出力ツリー内の絶対位置へのハードコードされた参照ではなく、テストランナーによって提供される runfiles イメージを介してこれらのファイルを読み込むようにする必要があります。

テストランナーの役割

テストランナーの観点から見ると、各テストは execve() で呼び出すことができるプログラムです。テストを実行する方法は他にもあります。たとえば、IDE では Java テストをインプロセスで実行できる場合があります。ただし、スタンドアロン プロセスとしてテストを実行した結果は、信頼できるものと見なす必要があります。テストプロセスが完了まで実行され、終了コード 0 で正常に終了した場合、テストは合格です。それ以外の結果はテストの失敗とみなされます。特に、文字列 PASS または FAIL を stdout に書き込んでも、テストランナーには意味がありません。

テストの実行に時間がかかりすぎたり、リソースの上限を超えたり、テストランナーが禁止されている動作を検出したりした場合、テストを強制終了して実行を失敗として扱うことがあります。ランナーは、テスト プロセスまたはその子プロセスにシグナルを送信した後、テストが合格したと報告してはなりません。

テスト ターゲット全体(個々のメソッドやテストではない)に、実行を完了するための制限時間が与えられます。テストの時間制限は、次の表に従って timeout 属性に基づいて設定されます。

timeout 制限時間(秒)
short 60
300
long 900
永遠 3600

タイムアウトを明示的に指定していないテストには、テストの size に基づく暗黙のタイムアウトが設定されます。

サイズ 暗黙のタイムアウト ラベル
short
long
巨大 永遠

タイムアウト設定が明示的に指定されていない「大規模」テストには、実行に 900 秒が割り当てられます。タイムアウトが「short」の「medium」テストには 60 秒が割り当てられます。

timeout とは異なり、size は、一般的な定義で説明されているように、テストをローカルで実行する際に、他のリソース(RAM など)の想定されるピーク使用率も決定します。

size ラベルと timeout ラベルのすべての組み合わせは有効であるため、「enormous」テストのタイムアウトを「short」と宣言できます。おそらく、非常に迅速に恐ろしいことを行うでしょう。

テストは、タイムアウトに関係なく任意に速く戻ることがあります。タイムアウトが長すぎてもテストにペナルティは課せられませんが、警告が発せられることがあります。一般的に、タイムアウトは、不安定さを招くことなくできるだけ短く設定する必要があります。

テストのタイムアウトは、遅いことがわかっている条件で手動で実行する場合、--test_timeout bazel フラグでオーバーライドできます。--test_timeout の値は秒単位です。たとえば、--test_timeout=120 はテストのタイムアウトを 2 分に設定します。

テスト タイムアウトの下限値の推奨値は次のとおりです。

timeout 最小時間(秒)
short 0
30
long 300
永遠 900

たとえば、「moderate」テストが 5.5 秒で完了した場合、timeout = "short" または size = "small" の設定を検討してください。bazel --test_verbose_timeout_warnings コマンドライン オプションを使用すると、指定されたサイズが大きすぎるテストが表示されます。

テストのサイズとタイムアウトは、こちらの仕様に従って BUILD ファイルで指定されます。指定しない場合、テストのサイズはデフォルトで「中」になります。

テストのメインプロセスが終了しても、その子プロセスの一部がまだ実行されている場合、テストランナーは実行が完了したとみなし、メインプロセスから観測された終了コードに基づいて成功または失敗としてカウントする必要があります。テストランナーは、不要なプロセスを強制終了する場合があります。テストでは、このような方法でプロセスをリークしてはなりません。

テストのシャーディング

テストは、テスト シャーディングによって並列化できます。テスト シャーディングを有効にするには、--test_sharding_strategyshard_count をご覧ください。シャーディングが有効になっている場合、テストランナーはシャードごとに 1 回起動されます。環境変数 TEST_TOTAL_SHARDS はシャード数で、TEST_SHARD_INDEX は 0 から始まるシャード インデックスです。ランナーは、この情報を使用して、実行するテストを選択します(ラウンドロビン戦略など)。すべてのテストランナーがシャーディングをサポートしているわけではありません。ランナーがシャーディングをサポートしている場合は、TEST_SHARD_STATUS_FILE で指定されたファイルの最終更新日を作成または更新する必要があります。それ以外の場合、--incompatible_check_sharding_support が有効になっていると、Bazel はテストがシャード化されている場合にテストを失敗させます。

初期条件

テストを実行する際、テストランナーは特定の初期条件を確立する必要があります。

テストランナーは、argv[0] のテスト実行可能ファイルへのパスを使用して各テストを呼び出す必要があります。このパスは相対パスで、テストの現在のディレクトリ(runfiles ツリー内、下記参照)の下にある必要があります。ユーザーが明示的に要求しない限り、テストランナーは他の引数をテストに渡すべきではありません。

初期環境ブロックは次のように構成されます。

変数 ステータス
HOME $TEST_TMPDIR の値 推奨
LANG 未設定 必須
LANGUAGE 未設定 必須
LC_ALL 未設定 必須
LC_COLLATE 未設定 必須
LC_CTYPE 未設定 必須
LC_MESSAGES 未設定 必須
LC_MONETARY 未設定 必須
LC_NUMERIC 未設定 必須
LC_TIME 未設定 必須
LD_LIBRARY_PATH 共有ライブラリを含むディレクトリをコロンで区切ったリスト オプション
JAVA_RUNFILES $TEST_SRCDIR の値 廃止
LOGNAME $USER の値 必須
PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:. 推奨
PWD $TEST_SRCDIR/workspace-name 推奨
SHLVL 2 推奨
TEST_INFRASTRUCTURE_FAILURE_FILE 書き込み可能なディレクトリ内のプライベート ファイルの絶対パス(このファイルは、テスト インフラストラクチャに起因する障害をレポートするためにのみ使用されるべきです。テストの不安定な障害をレポートするための一般的なメカニズムとして使用されるべきではありません)。このコンテキストでは、テスト インフラストラクチャは、テスト固有ではないが、誤動作によってテストの失敗を引き起こす可能性のあるシステムまたはライブラリとして定義されます。1 行目は失敗の原因となったテスト インフラストラクチャ コンポーネントの名前、2 行目は失敗の人間が読める形式の説明です。追加の行は無視されます)。 オプション
TEST_LOGSPLITTER_OUTPUT_FILE 書き込み可能なディレクトリ内のプライベート ファイルへの絶対パス(Logsplitter protobuffer ログの書き込みに使用) オプション
TEST_PREMATURE_EXIT_FILE 書き込み可能なディレクトリ内のプライベート ファイルへの絶対パス(exit() への呼び出しをキャッチするために使用) オプション
TEST_RANDOM_SEED --runs_per_test オプションを使用すると、個々のテスト実行ごとに TEST_RANDOM_SEEDrun number(1 から始まる)に設定されます。 オプション
TEST_RUN_NUMBER --runs_per_test オプションを使用すると、個々のテスト実行ごとに TEST_RUN_NUMBERrun number(1 から始まる)に設定されます。 オプション
TEST_TARGET テスト対象のターゲットの名前 オプション
TEST_SIZE テスト size オプション
TEST_TIMEOUT テスト timeout(秒単位) オプション
TEST_SHARD_INDEX sharding が使用されている場合は、シャード インデックス オプション
TEST_SHARD_STATUS_FILE sharding のサポートを示すためにタッチするファイルのパス オプション
TEST_SRCDIR runfiles ツリーのベースへの絶対パス 必須
TEST_TOTAL_SHARDS sharding が使用されている場合は、合計 shard count> オプション
TEST_TMPDIR 書き込み可能なプライベート ディレクトリへの絶対パス 必須
TEST_WORKSPACE ローカル リポジトリのワークスペース名 オプション
TEST_UNDECLARED_OUTPUTS_DIR 書き込み可能な非公開ディレクトリの絶対パス(宣言されていないテスト出力の書き込みに使用されます)。TEST_UNDECLARED_OUTPUTS_DIR ディレクトリに書き込まれたファイルはすべて圧縮され、bazel-testlogsoutputs.zip ファイルに追加されます。 オプション
TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR 非公開の書き込み可能なディレクトリへの絶対パス(未宣言のテスト出力アノテーション .part ファイルと .pb ファイルの書き込みに使用されます)。 オプション
TEST_WARNINGS_OUTPUT_FILE 書き込み可能なディレクトリ内のプライベート ファイルへの絶対パス(テスト ターゲットの警告の書き込みに使用) オプション
TESTBRIDGE_TEST_ONLY --test_filter の値(指定されている場合) オプション
TZ UTC 必須
USER getpwuid(getuid())->pw_name の値 必須
XML_OUTPUT_FILE テスト アクションがテスト結果の XML 出力ファイルを書き込む場所。それ以外の場合、Bazel はテスト アクションの一部としてテストログをラップするデフォルトの XML 出力ファイルを生成します。XML スキーマは JUnit テスト結果スキーマに基づいています。 オプション
BAZEL_TEST テスト実行可能ファイルが bazel test によって駆動されていることを示します 必須

環境には追加のエントリが含まれている場合があります。テストは、上記に記載されていない環境変数の有無や値に依存してはなりません。

初期作業ディレクトリは $TEST_SRCDIR/$TEST_WORKSPACE とします。

現在のプロセス ID、プロセス グループ ID、セッション ID、親プロセス ID は指定されていません。このプロセスは、プロセス グループ リーダーまたはセッション リーダーである場合とそうでない場合があります。プロセスに制御端末がある場合とない場合があります。プロセスには、実行中または未回収の子プロセスが 0 個以上存在する可能性があります。テストコードが制御を取得したときに、プロセスに複数のスレッドがあってはなりません。

ファイル記述子 0(stdin)は読み取り用に開いている必要がありますが、何に接続されているかは指定されていません。テストで読み取ってはなりません。ファイル記述子 1(stdout)と 2(stderr)は書き込み用に開いている必要がありますが、それらが何に接続されているかは指定されていません。端末、パイプ、通常のファイルなど、文字を書き込めるものであれば何でも構いません。オープン ファイル テーブルのエントリを共有する場合があります(つまり、独立してシークできません)。テストは、他の開いているファイル記述子を継承してはなりません。

初期 umask は 022 または 027 とします。

アラームまたはインターバル タイマーが保留中ではないこと。

ブロックされたシグナルの初期マスクは空であるものとします。すべてのシグナルはデフォルトのアクションに設定されます。

初期リソースの上限(ソフトとハードの両方)は、次のように設定する必要があります。

リソース 上限
RLIMIT_AS 無制限
RLIMIT_CORE 指定なし
RLIMIT_CPU 無制限
RLIMIT_DATA 無制限
RLIMIT_FSIZE 無制限
RLIMIT_LOCKS 無制限
RLIMIT_MEMLOCK 無制限
RLIMIT_MSGQUEUE 指定なし
RLIMIT_NICE 指定なし
RLIMIT_NOFILE 1024 以上
RLIMIT_NPROC 指定なし
RLIMIT_RSS 無制限
RLIMIT_RTPRIO 指定なし
RLIMIT_SIGPENDING 指定なし
RLIMIT_STACK 無制限、または 2044KB <= rlim <= 8192KB

初期プロセス時間(times() によって返される)とリソース使用率(getrusage() によって返される)は指定されていません。

初期のスケジューリング ポリシーと優先度が指定されていません。

ホストシステムの役割

テストランナーが直接制御するユーザー コンテキストの側面に加えて、テストが実行されるオペレーティング システムは、テスト実行が有効になるための特定のプロパティを満たしている必要があります。

ファイルシステム

テストで観測されるルート ディレクトリは、実際のルート ディレクトリである場合もそうでない場合もあります。

/proc を取り付けなければならない。

すべてのビルドツールは、ローカル インストールで使用される /usr の絶対パスに存在する必要があります。

/home で始まるパスは使用できない場合があります。テストでは、このようなパスにアクセスしないでください。

/tmp は書き込み可能ですが、テストではこれらのパスの使用を避けるべきです。

テストでは、排他的使用のために定数パスが利用可能であることを想定してはなりません。

テストでは、マウントされたファイル システムで atime が有効になっていることを前提としてはなりません。

ユーザーとグループ

ユーザー root、nobody、unittest が存在する必要があります。グループ root、nobody、eng が存在する必要があります。

テストは root 以外のユーザーとして実行する必要があります。実ユーザー ID と有効ユーザー ID は同じである必要があります。グループ ID も同様です。これ以外に、現在のユーザー ID、グループ ID、ユーザー名、グループ名は指定されていません。補助グループ ID のセットは指定されていません。

現在のユーザー ID とグループ ID には、getpwuid()getgrgid() で取得できる対応する名前が必要です。補助グループ ID については、同じことが当てはまらない場合があります。

現在のユーザーにホーム ディレクトリが必要です。書き込み可能でない可能性があります。テストで書き込みを試みてはなりません。

ネットワーキング

ホスト名が指定されていません。ドットが含まれる場合と含まれない場合があります。ホスト名を解決すると、現在のホストの IP アドレスが返される必要があります。最初のドットの後にホスト名を解決することもできます。ホスト名 localhost が解決される必要があります。

その他のリソース

テストには少なくとも 1 つの CPU コアが割り当てられます。他の方法も利用できる場合がありますが、保証はされません。このコアの他のパフォーマンスの側面は指定されていません。テストルールに「cpu:n」(n は正の数)というタグを追加することで、予約をより多くの CPU コア数に増やすことができます。マシンにリクエストされた CPU コアの合計数よりも少ない場合でも、Bazel はテストを実行します。テストでシャーディングを使用する場合、個々のシャードはここで指定された数の CPU コアを予約します。

テストではサブプロセスを作成できますが、プロセス グループやセッションは作成できません。

テストで使用できる入力ファイルの数には上限があります。この上限は変更される可能性がありますが、現在のところ数万件の入力の範囲内です。

日時

現在の日時が指定されていません。システムのタイムゾーンが指定されていません。

X Windows は利用できる場合と利用できない場合があります。X サーバーが必要なテストでは、Xvfb を起動する必要があります。

ファイルシステムとのやり取りをテストする

テスト環境変数で指定されたすべてのファイルパスは、特に指定がない限り、ローカル ファイル システムのどこかを指します。

テストでは、$TEST_TMPDIR$TEST_UNDECLARED_OUTPUTS_DIR(設定されている場合)で指定されたディレクトリ内でのみファイルを作成する必要があります。

これらのディレクトリは最初は空です。

テストでは、これらのディレクトリの削除、chmod、その他の変更を試みてはなりません。

これらのディレクトリはシンボリック リンクの場合があります。

$TEST_TMPDIR/. のファイル システム タイプは指定されていません。

テストでは、宣言されていない出力ファイルにアノテーションを付けるために、$TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR に .part ファイルを書き込むこともあります。

まれに、テストで /tmp にファイルの作成を強制する必要があることがあります。たとえば、Unix ドメイン ソケットのパス長の制限では、通常、/tmp の下にソケットを作成する必要があります。Bazel はこのようなファイルを追跡できません。テスト自体が、他の同時実行テストやテスト以外のプロセスと競合しないように一意のパスを使用し、/tmp で作成したファイルをクリーンアップするように、密閉性を確保する必要があります。

JUnit4 TemporaryFolderGo TempDir などの一般的なテスト フレームワークには、/tmp の下に一時ディレクトリを作成する独自の方法があります。これらのテスト フレームワークには /tmp のファイルをクリーンアップする機能が含まれているため、TEST_TMPDIR の外部にファイルを作成する場合でも使用できます。

テストでは、runfiles メカニズム、または入力ファイルを指定するために特別に設計された実行環境の他の部分を介して入力にアクセスする必要があります。

テストは、独自の実行可能ファイルの場所から推測されるパスでビルドシステムの他の出力にアクセスしてはなりません。

runfiles ツリーに通常のファイル、シンボリック リンク、またはその両方が含まれるかどうかは指定されていません。runfiles ツリーには、ディレクトリへのシンボリック リンクが含まれている場合があります。テストでは、runfiles ツリー内の .. コンポーネントを含むパスを使用しないでください。

runfiles ツリー内のディレクトリ、ファイル、シンボリック リンク(シンボリック リンクをトラバースするパスを含む)は書き込み可能であってはなりません。(したがって、初期作業ディレクトリは書き込み可能にすべきではありません)。テストでは、実行ファイルのどの部分も書き込み可能であることや、現在のユーザーが所有していることを前提としてはなりません(たとえば、chmodchgrp は失敗する可能性があります)。

ランファイル ツリー(シンボリック リンクをトラバースするパスを含む)は、テスト実行中に変更してはなりません。親ディレクトリとファイル システムのマウントは、ランファイル ツリー内のパスの解決結果に影響するような変更を加えてはなりません。

早期終了をキャッチするために、テストは開始時に TEST_PREMATURE_EXIT_FILE で指定されたパスにファイルを作成し、終了時に削除できます。テストの終了時に Bazel がファイルを確認すると、テストが途中で終了したと見なされ、失敗としてマークされます。

タグの規則

テストルールのタグには、特別な意味を持つものがあります。tags 属性に関する Bazel ビルド百科事典もご覧ください。

タグ 意味
exclusive 同時に他のテストを実行しない
external テストに外部依存関係があるため、テスト キャッシュを無効化
large test_suite 規約、大規模なテストのスイート
manual * :...:*:all などのワイルドカード ターゲット パターンにテスト ターゲットを含めない
medium test_suite 規約、中規模テストのスイート
small test_suite 規約、小規模なテストのスイート
smoke test_suite 規約。コード変更をバージョン管理システムに commit する前に実行する必要があることを意味します。

Runfiles

以下では、//foo/bar:unittest というラベルの *_binary() ルールがあり、//deps/server:server というラベルのルールに実行時の依存関係があるとします。

場所

ターゲット //foo/bar:unittest のランファイル ディレクトリは、ディレクトリ $(WORKSPACE)/$(BINDIR)/foo/bar/unittest.runfiles です。このパスは runfiles_dir と呼ばれます。

依存関係

runfiles ディレクトリは、*_binary() ルールのコンパイル時依存関係として宣言されます。runfiles ディレクトリ自体は、*_binary() ルールまたはそのコンパイル時または実行時の依存関係に影響する BUILD ファイルのセットに依存します。ソースファイルを変更しても、runfiles ディレクトリの構造には影響しないため、再構築はトリガーされません。

目次

runfiles ディレクトリには次のものが含まれています。

  • 実行時依存関係へのシンボリック リンク: *_binary() ルールの実行時依存関係である各 OutputFile と CommandRule は、runfiles ディレクトリ内の 1 つのシンボリック リンクで表されます。シンボリック リンクの名前は $(WORKSPACE)/package_name/rule_name です。たとえば、サーバーのシンボリック リンクの名前は $(WORKSPACE)/deps/server/server になり、フルパスは $(WORKSPACE)/foo/bar/unittest.runfiles/$(WORKSPACE)/deps/server/server になります。シンボリック リンクの宛先は、OutputFile または CommandRule の OutputFileName() で、絶対パスとして表されます。したがって、シンボリック リンクの宛先は $(WORKSPACE)/linux-dbg/deps/server/42/server になる可能性があります。
  • サブ ランファイルへのシンボリック リンク: *_binary() C の実行時の依存関係であるすべての *_binary() Z について、C のランファイル ディレクトリに Z のランファイルへの 2 つ目のリンクがあります。シンボリック リンクの名前は $(WORKSPACE)/package_name/rule_name.runfiles です。シンボリック リンクのターゲットは runfiles ディレクトリです。たとえば、すべてのサブプログラムが共通の runfiles ディレクトリを共有します。