百科事典をテストする

問題を報告 ソースを表示

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

背景情報

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

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

ユーザーはテストバイナリを直接実行することもできます。このような呼び出しは許可されていますが、承認されるものではありません。このような呼び出しは、以下の要件を遵守しません。

テストは密閉型である必要があります。つまり、依存関係が宣言されているリソースにのみアクセスする必要があります。テストが密閉型でなければ、歴史的に再現可能な結果が得られません。これは、犯人の検出(テストに影響を与えた変更の特定)、リリース エンジニアリングの監査可能性、テストのリソース分離にとって重大な問題になる可能性があります(自動テスト フレームワークは、一部のテストがたまたま通信しているため、サーバーを DDOS しないでください)。

目的

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

テスト環境の仕様により、テスト作成者は指定の動作に依存しないため、テスト インフラストラクチャで実装を変更する自由度が向上します。この仕様では、密閉性、決定性、再入可能性が適切でなくても、現在多くのテストに合格できるよう、いくつかの穴が狭くなっています。

このページは規範的で信頼できるものであることを意図しています。この仕様とテストランナーの実装動作が一致しない場合は、仕様が優先されます。

提案された仕様

キーワード「しなければならない」、「してはならない」、「必須」、「するべき」、「べきでない」、「すべきである」、「すべきです」、「推奨」、「しても構いません」、「任意」は、IETF RFC 2119 で定義されているように解釈されます。

テストの目的

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

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

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

現時点では、このような動作は適用されません。ただし、テストランナーは、今後このような適用を追加する権限を有します。

ビルドシステムの役割

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

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

テストランナーのロール

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

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

個々のメソッドやテストではなく、テスト ターゲット全体に対して、完了までの実行時間が与えられます。次の表に示すように、テストの制限時間は timeout 属性に基づきます。

タイムアウト 制限時間(秒)
short 60
中程度に 300
long 900
永遠 3,600

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

サイズ 暗黙のタイムアウト ラベル
小さく初めて short
medium 中程度に
long
膨大な 永遠

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

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

size ラベルと timeout ラベルのすべての組み合わせは正しいため、「enormous」テストではタイムアウト「short」を指定して宣言できます。恐ろしいことをすぐに実行してしまうでしょう

テストは、タイムアウトに関係なく任意の速度で返される場合があります。過剰なタイムアウトによってテストにペナルティが生じることはありませんが、警告が発行される場合があります。通常は、タイムアウトを可能な限り厳しく設定し、不具合が発生することはありません。

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

次に示すように、テスト タイムアウトの推奨下限も存在します。

タイムアウト 最小時間(秒)
short 0
中程度に 30
long 300
永遠 900

たとえば、「中程度」のテストが 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 合計 shard countsharding が使用されている場合) 省略可
TEST_TMPDIR 書き込み可能な非公開ディレクトリへの絶対パス 不要です
TEST_WORKSPACE ローカル リポジトリのワークスペース名 省略可
TEST_UNDECLARED_OUTPUTS_DIR 書き込み可能なプライベート ディレクトリへの絶対パス(宣言されていないテスト出力の書き込みに使用されます)。TEST_UNDECLARED_OUTPUTS_DIR ディレクトリに書き込まれたファイルはすべて zip 圧縮され、bazel-testlogs の下の outputs.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 unlimited
RLIMIT_CORE 未設定
RLIMIT_CPU unlimited
RLIMIT_DATA unlimited
RLIMIT_FSIZE unlimited
RLIMIT_LOCKS unlimited
RLIMIT_MEMLOCK unlimited
RLIMIT_MSGQUEUE 未設定
RLIMIT_NICE 未設定
RLIMIT_NOFILE 1,024 以上
RLIMIT_NPROC 未設定
RLIMIT_RSS unlimited
RLIMIT_RTPRIO 未設定
RLIMIT_SIGPENDING 未設定
RLIMIT_STACK 無制限、または 2,044 KB <= rlim <= 8,192 KB

初期プロセス時間(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/. のファイルシステム タイプは未指定のままです。

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

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

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

テストは、runfile メカニズム、または入力ファイルを利用可能にすることを目的とした実行環境の他の部分を通じて、入力にアクセスする必要があります。

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

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

実行ファイル ツリー内のディレクトリ、ファイル、シンボリック リンク(シンボリック リンクを走査するパスを含む)は、書き込み可能にしないでください。(最初の作業ディレクトリが書き込み可能にならないようにする必要があります)。テストでは、runfile の一部が書き込み可能である、または現在のユーザーが所有しているとは想定しないでください(たとえば、chmodchgrp が失敗する可能性があります)。

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

早期終了をキャッチするために、テストの開始時に TEST_PREMATURE_EXIT_FILE で指定されたパスにファイルを作成し、テスト終了時にファイルを削除できます。テストの完了時に Bazel でファイルが検出された場合は、テストが早期に終了したと見なされ、不合格としてマークされます。

タグの規則

テストルール内のタグの中には、特別な意味を持つものがあります。tags 属性に関する Bazel ビルド エンサイクロペディアもご覧ください。

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

実行ファイル

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

ロケーション

ターゲット //foo/bar:unittest の runfiles ディレクトリは $(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 の runfiles ディレクトリ内に Z のランファイルへの 2 つ目のリンクがあります。シンボリック リンクの名前は $(WORKSPACE)/package_name/rule_name.runfiles です。シンボリック リンクのターゲットは runfiles ディレクトリです。たとえば、すべてのサブプログラムは共通の runfile ディレクトリを共有します。