本テストツールは主に HWPOISON サブシステムのカーネル開発を推進するために、関連するテストケースをメンテ・共有するものです。
前提条件として、テストを走行するシステムに以下のパッケージがインストールされている必要があります。
gcc
ruby
numactl
numactl-devel
(on RHEL/Fedora),libnuma-dev
(on Ubuntu)
その他、テストケースによっては追加でライブラリやツールが必要となることもあります。 それらが不足している場合、エラーメッセージ等で分かるようになっているはずなので、適宜インストールしてください。 また、環境がテストケースの要件を満たしていない場合、そのテストケースの実行はスキップされます。
以下では基本的な使い方として、全テストケースを実行する場合と指定したテストケースを実行する場合について説明します。
本テストツールは全て root ユーザで実行することを想定しています。
以下のように実行することで、デフォルトで走行対象になっている全テストケースを、フォアグラウンドで実行します。
$ git clone https://github.com/Naoya-Horiguchi/mm_regression
$ cd mm_regression
$ make
$ ./run.sh prepare debug
$ ./run.sh project run
指定したテストケースを実行するには、./run.sh recipe list
でテストケース一覧を表示し、適宜フィルタして work/debug/recipelist
(debug
は後述のテストプロジェクト名) に書き込み、その後 ./run.sh project run
を実行する。
$ make
$ ./run.sh prepare debug
$ ./run.sh recipe list | grep <string> > work/debug/recipelist
$ ./run.sh project run
テスト走行条件や走行するテストケースを細かく指定したいことがあります。 以下では、そのために定義された概念や設定、走行方法について説明します。
同じ条件 (サーバ、カーネル、パラメータなど) 下で、テストケースのセットと、各テストケースの走行結果をひとまとめにした概念をテストプロジェクトとします。
テストプロジェクトは走行前に定義する必要があり、上記コマンドの ./run.sh prepare debug
はテストプロジェクト debug
を定義しています。
テストプロジェクト名はテスト実行中は環境変数 RUNNAME
により参照されます。
テストを実行すると走行結果は全てディレクトリ work/$RUNNAME
配下に記録されます。
このディレクトリ配下には簡単な環境情報 (work/$RUNNAME/environment
) や各テストケースのレシピ (後述) を格納しているため、work
配下を保管することで、テストプロジェクトごとにどのような環境・設定でどのようなテストケースを実行したか整理して記録できます。
テストプロジェクトの設定ファイルは work/$RUNNAME/config
です。
例えば以下のような構成をしています。
この設定ファイルはテスト実行時に bash の環境変数として読み込まれ、テストの動作に影響を与えます
(各環境変数の意味の詳細については「その他、テスト実行に関する tips」を参照)。
$ cat work/debug/config
export RUNNAME=debug
export RUN_MODE=all
export SOFT_RETRY=1
export HARD_RETRY=1
export TEST_DESCRIPTION="MM regression test"
export UNPOISON=false
export FAILRETRY=
export PRIORITY=0-20
export BACKWARD_KEYWORD=
export FORWARD_KEYWORD=
export LOGLEVEL=1
その他、テストケースによっては固有の環境変数が与えられている前提のものがあります。
例えば KVM ゲストを用いるテストケースは仮想マシン名を環境変数 VM=...
で与える必要があります。
テストケースはレシピファイルで管理され、基本的に 1 つのレシピファイルで 1 つのテストケースを定義します。
レシピファイルは cases
配下に格納され、ファイルパスがテストケースの ID となります。
テンプレートをサポートしていて、類似するテストケースをテンプレートから自動生成することで、効率よくテストケースを記述できるようにしています。
拡張子 .set3
を持つレシピファイルは、テンプレートを用いて書かれたテストケースで、./run.sh recipe split
コマンドにより拡張子 .auto3
を持つレシピファイルが生成されます。
定義済みのレシピ一覧を表示するには ./run.sh recipe list
を実行します。
テストタイプ、優先度の情報を含むレシピ一覧を表示するには ./run.sh recipe list -p
を実行します。
テストケースの記述方法については「テストケースの構成」を参照。
./run.sh prepare
コマンドでテストプロジェクトを作成すると、
全テストケースのリストが work/$RUNNAME/full_recipe_list
に保存されます。
テストの実行時には、設定ファイルで与えられた環境変数を元に full_recipe_list
から実行すべきテストケースを判断し、順次実行します。
実行したいテストケースが全テストケースの一部のみの場合、full_recipe_list
の中から選択したテストケースを work/$RUNNAME/recipelist
に書き込むことで、走行対象のテストケースを指定します。
現在のテストプロジェクトを知るためには ./run.sh project show
コマンドを実行します。
$ ./run.sh proj show
Project Name: debug
Total testcases: 531
Target testcases: 531
現在のテストプロジェクトの進行状態を知るには ./run.sh project summary
コマンドを実行します。
$ ./run.sh proj summary
Project Name: debug
Progress: 394 / 525 (75%)
PASS 350, FAIL 26, WARN 0, SKIP 18, NONE 131
テストケース単位で細かい結果を知りたい場合は -p
オプションが便利です。
$ ./run.sh proj summary -p
Project Name: 220506a
PASS mm/compaction
FAIL mm/hugetlb/deferred_dissolve/error-type-hard-offline_dissolve-dequeue.auto3
PASS mm/hugetlb/deferred_dissolve/error-type-hard-offline_dissolve-free.auto3
FAIL mm/hugetlb/deferred_dissolve/error-type-soft-offline.auto3
SKIP mm/hugetlb/deferred_dissolve_fault.auto3
PASS mm/hugetlb/dissolve_failure
PASS mm/hugetlb/per_process_usage_counter
...
Progress: 394 / 525 (75%)
テストを中断したり、テスト中に再起動が発生した場合、./run.sh project run
を実行すると中断したテストケースからテストを再開します。
中断状態をクリアして最初から再実行したい場合は、-a
オプションを指定します。
再実行時に既に PASS したテストケースは無視したいことがあります。
その場合は -a -p
オプションを指定します。
テスト実行中にカーネルパニック等により再起動した場合、同じテストケースから再開しても再起動を繰り返すため、テストが進行しないという状況があります。
これを回避するには -w
オプションを指定して実行します。
その他、テスト走行に関する細かい要求を実現するために、本テストツールは以下のような機能を持っています。 これらは全て環境変数によってコントロールされます。
RUN_MODE
: 各テストケースにはTEST_TYPE
が定義されています (明示的に定義していない場合は normal)。環境変数RUN_MODE
はTEST_TYPE
に応じてテストケースを実行するかどうかの判断に使用され、TEST_TYPE
がRUN_MODE
で指定されたタイプに一致する場合、そのテストケースは実行され、そうでない場合は SKIP となります。RUN_MODE=all
は特殊な値で、TEST_TYPE
に関わらず全てのテストケースが実行されます。RUN_MODE
はカンマ区切りで複数のタイプを指定することができます。- テストケース側でも
TEST_TYPE
はカンマ区切りで複数のタイプを指定でき、全てのタイプがRUN_MODE
で指定されている場合のみ、そのテストケースは実行されます。
SOFT_RETRY
: デフォルトは 3 で、あるテストケースをSOFT_RETRY
回実行して 1 回でも成功すればそのテストケースはパスしたとみなします。HARD_RETRY
: デフォルトは 1 で、あるテストケースをHARD_RETRY
回実行して全て成功すればそのテストケースはパスしたとみなします。SOFT_RETRY
とHARD_RETRY
の両方を 2 以上にした場合、SOFT_RETRY
回失敗するまでに「HARD_RETRY
回連続で成功」すればパスとみなします。FAILRETRY
: TODOPRIORITY
: 各テストケースにはテストごとの優先度が定められています。0-20 までの数字で表現され、数字が小さいほど優先度が高いとみなします。環境変数PRIORITY
は実行するテストケースの優先度範囲を指定します。PRIORITY=0-10,12,15-18
のようにカンマ区切りで複数回指定することや、ハイフンで範囲指定することができます。デフォルトはPRIORITY=0-10
です。BACKWARD_KEYWORD
: テスト対象のカーネルや実行環境のバージョンによっては、期待動作が変わることがあります。この環境変数にキーワードを指定した時、そのキーワードに紐付けられた期待動作として古い期待動作を採用します。upstream カーネルに新機能が入り、そのカーネルがパスするようテストケースは追随しつつ、古いカーネルでも正しくテストしたい場合に有用です。FORWARD_KEYWORD
:BACKWARD_KEYWORD
と同様、期待動作の異なる振る舞いを選択するための環境変数です。この環境変数にキーワードを指定した時、そのキーワードに紐付けられた期待動作として新しい期待動作を採用します。今すぐ upstream に入る機能ではないが、開発版のカーネルでパスするテストケースを書きたい場合に有用です。LOGLEVEL
: 数値をセットしてログレベルを指定します。デフォルトは 1 で、 2 にするとログが増え、0 にするとログを減らせます。
以下では、テストケース開発者向けに、本テストツールの走行の流れやテストケースの追加方法について説明します。
一つのテストケースは一つのレシピファイルで定義されます。 レシピファイルは基本的には bash シェルスクリプトです。 レシピファイルはそのテストケース内だけで有効な変数を定義することができ、以下の 4 つの関数を実行します。
_prepare()
: テストケースを実行する際の事前条件チェックや準備処理を記述します。テストケースを実行する条件を満たしていなかったり、準備処理に失敗した場合は非ゼロを返し、その場合テストロジック (_control()
) は実行されません。_control()
: テストケースを実現するためのロジックを記述します。_cleanup()
:_prepare()
に副作用を伴う準備処理が実行された場合、それをクリーンアップする処理を記述します。_check()
:_control()
処理中に採取した情報をベースにテストの pass/fail 判定する必要がある場合に処理を記述します。
これらが必要かどうかはテストケースに依存しており、単純なものでは _control()
しか持たないテストケースもあります。
pass/fail 判定は返り値ベースだと解像度が足りないので、カスタムリターンコードを使用します。
テストケースに変数 EXPECTED_RETURN_CODE
が指定されているとき、テスト走行中に期待通りのコードパスを通ったかどうかをチェックします。
EXPECTED_RETURN_CODE="START CHECK1 END"
_control() {
set_return_code START
test_logic
if [ $? -eq 0 ] ; then
set_return_code CHECK1
fi
...
set_return_code END
}
この場合、test_logic が成功して if 文内を通った場合にパスします。 理解しやすいリターンコードを定義することで、期待動作を管理しやすくなります。
本テストツールは、work/$RUNNAME/recipelist
で指定されたテストケースのリストを上から順番に実行します。
レシピファイルの階層構造には意味があり、各ディレクトリごとに管理用のサブプロセスを作成し、各テストケースは別のサブプロセスで実行されます。
これはディレクトリ単位で環境変数を効率よく継承させていくとともに、あるテストケースのために定義した変数や関数が後のテストケースの動作に干渉することを避けられます。
例えば、下記のような recipelist
があったとします。
cases/test1
cases/dir1/test2
cases/dir1/dir2/test3
cases/dir1/test4
cases/test5
この場合、以下の様な流れに沿ってテストケースは実行されます。
main thread
|---> sub thread
| run cases/test1
|---> sub thread
| (source cases/dir1/config)
| |---> sub thread
| | run cases/dir1/test2
| |---> sub thread
| | (source cases/dir1/dir2/config)
| | |---> sub thread
| | | run cases/dir1/dir2/test3
| | (dir_cleanup() in cases/dir1/dir2/config)
| |---> sub thread
| | run cases/dir1/test4
| (dir_cleanup() in cases/dir1/config)
|---> sub thread
| run cases/test5
*
各テストケースごとにサブスレッドで実行されるだけでなく、ディレクトリを下る際にもサブスレッドを生成しています。
あるディレクトリ配下の全てのテストに共通の設定を config
ファイルに書くことによって、共通の準備処理や事前チェックをまとめて行うことができます。
また、config
内に関数 dir_cleanup()
を定義することにより、共通のクリーンナップ処理を実行できます。
以下の変数はテストケースのコンテキストで利用できる変数です。
TRDIR
: このテストツールのトップディレクトリのパスを格納しています。TCDIR
: test_core モジュールのディレクトリパスを格納しています (TCDIR=$TRDIR/test_core
)。TDIR
: 個々のテストケースで使用される一時ディレクトリのパスを格納しています (TDIR=$TRDIR/tmp
)。WDIR
: テストプロジェクトの結果・進捗に関する情報を保存するためのディレクトリのパスを格納します (WDIR=$TRDIR/work
)。GTMPD
: テストプロジェクトのディレクトリ (work/$RUNNAME
) を指します。テストをコントロールするためのファイルがいくつか格納されています。RTMPD
: 各テストケースの情報を格納するディレクトリを指します。例えばcases/dir1/test2
というテストケースの実行時は、RTMPD=work/$RUNNAME/dir1/test2
となります。TMPD
: 各リトライラウンドごとの情報を格納するディレクトリを指します。例えば、SOFT_RETRY
の 2 回目、HARD_RETRY
の 3 回目のラウンドでは、TMPD=$RTMPD/2-3
となります。テストロジックの中間ファイルは基本的にこのディレクトリ配下に保存するようにします。
以下はテストケース内で定義することでテストの動作に影響を与える変数です。
MAX_REBOOT
: リブートを想定したテストケースにおいて、無限にリブートをループするのを防ぐため、リブート回数の最大値を設定します。デフォルトは 0 です。TEST_PRIORITY
: テストの優先度を設定します。デフォルトは 10 です。テストケースの中には時間がかかるものや重要度が低いものがあるので、テストを走行する・しない、あるいは走行順序を指定するのに利用します。TEST_TYPE
: 開発中のテストや、他の理由でテストケースにタグをつけたい時に利用します。コンマ区切りの文字列として複数指定することができます。デフォルト値normal
以外に設定した場合、そのテストケースはデフォルトではスキップされます。そのテストケースを走行させるためには、環境変数RUN_MODE
をTEST_TYPE
のキーワードのどれか一つにセットする必要があります。テストケースのTEST_TYPE
の一覧を取得するためにはmake recipe_priority
コマンドを実行します。
- 全テストを流す場合、カーネルパニック発生時に再起動する仕組み (ダンプを設定したり、ブートパラメータ
panic=<N>
を指定する) を有効にしておくのが望ましいです。