北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

cargo test --jobs N -- --test-threads=M

redis-rs の cluster のテストが何度やっても通らなくてハマった。ただし、テスト名を指定して一個ずつであれば成功する。該当するテストは以下。

redis-rs/test_cluster.rs at bd8dc731ded564329d74717dfacc5cce748d891f · mitsuhiko/redis-rs · GitHub

このテストは redis server を立ち上げてクラスタを組んでテストを実行している。このとき、各サーバには 7000 番ポートから順番に割り当てている。

redis-rs/cluster.rs at bd8dc731ded564329d74717dfacc5cce748d891f · mitsuhiko/redis-rs · GitHub

そして、デフォルトでは cargo test 1 は複数のテストを並列に実行する。直列な世界に生きているので、ここに気がつくまでに時間がかかってしまった。

テストの実行ファイルでヘルプを表示させると、デフォルトでは並列実装すると書いてある。

$ target/debug/deps/test_cluster-cdbee22b93a5c3e7 --help
Usage: --help [OPTIONS] [FILTER]                                                                                                                                                                                                                        
Options:
..snip..
        --test-threads n_threads
                        Number of threads used for running tests in parallel
..snip..
By default, all tests are run in parallel. This can be altered with the
--test-threads flag or the RUST_TEST_THREADS environment variable when running
tests (set it to 1).
..snip..

実際、 rustc 側で実装を見ると、デフォルトは CPU コア数であることがわかる。

rust/concurrency.rs at 4ae328bef47dffcbf363e5ae873f419c06a5511d · rust-lang/rust · GitHub

並列で実行すると test_cluster.rs が落ちるのは明確だ。 7000 番 port が競合しているので、それぞれのテストで使う redis のサーバが建てられなくなってしまう。直列で実行するしかない。

redis-rs のリポジトリには、 Makefile があり、そこで --test-threads が指定されている。これはテストの実行ファイルが持つオプションなので cargo に直接渡すことはできず、 -- --test-threads=1 というように -- の後ろに指定しなければならない。

redis-rs/Makefile at bd8dc731ded564329d74717dfacc5cce748d891f · mitsuhiko/redis-rs · GitHub

ところで、 --test-threads=1 とは別に、 cargo には --jobs というオプションがある。

$ cargo test --help
..snip..
    -j, --jobs <N>                   Number of parallel jobs, defaults to # of CPUs
..snip..

ドキュメントは以下にある。紛らわしいが、実行ファイルのビルドに使う CPU 数を指定するオプションらしい。

doc.rust-lang.org

The --jobs argument affects the building of the test executable but does not affect how many threads are used when running the tests.

今回のように「単体テストが逐次実行しかできない」という場合には --jobs ではなく --test-threads を使わねばならない。指定先も cargo に指定するのか単体テストの実行ファイル側に指定するのかも別れていてわかりにくい。

そもそも、「単体テストが逐次実行しかできない」という状況がイケてないなあとは思う。


  1. 正確には、テストの実行ファイルである。