Rust の cargo test でセキュリティソフトと格闘していたら doctest 激重問題が解消された件

こんにちは。Rust の doctest まわりでひとつ問題回避に成功したので、メモとして残しておきます。

doctest でエラー発生

先ほど元気に Rust の開発をしていたら、doctest で以下のようなテストが出てしまいました。

doctest errors

このエラーが出る前に、そういえば下のようなポップアップが出ていたような気がします。

セキュリティソフトの警告

見るからに、doctest を実行するときに生成された実行ファイルを消しにかかったな・・・ということで、回避のために奮闘しました。

回避策を模索

まずなによりセキュリティソフトの設定で例外設定を試みます。オンラインドキュメントを見ると「例外のファイルとかフォルダとか設定できるよ!」とのこと。早速設定しようとしたのですが、上記のファイルの場所からわかる通り、実行の際にフォルダ名を自動生成しているようで、直接指定は適いそうにありません。かといって %USERPROFILE%\AppData\Local\Temp を例外設定してしまうのはセキュリティ的に不安しかありません。

そこで cargo test で生成される一時ファイルの保存先を変える方法はないか・・・と思ってググったところ、まさに同じ状況のやり取りが見つかりました↓
github.com
要は「一時フォルダを指定する環境変数を、テストの実行直前に書き換えればOK」ということのようです。

解決編

上を組み合わせて以下のようにしてみました (OS は Windows11 で, PowerShell 上で実行の例):

  1. 適当な場所に作業用フォルダを作り、セキュリティソフトの例外設定をしておく
  2. 上記フォルダを環境変数に登録しておく (今回は TEMP_NO_SECURITY にします)
  3. テスト実行時に直前で環境変数 TMP を TEMP_NO_SECURITY に書き換え + テスト実行後に戻し (私の環境では TEMP も同じ値を入れているので、それで上書き)*1
PS $> $env:TMP=$env:TEMP_NO_SECURITY; cargo test --release; $env:TMP=$env:TEMP

これによりセキュリティソフトの監視から外れて無事テストを実行できるようになりました。
上記リンク先にあるように、これは windows の一時フォルダの取得先を変更していることに起因するので、Rust のコード自身が一時フォルダを参照するものであれば挙動が変更しうることには注意してください。
めでたしめでたし。

うれしい副産物編

で、めでたいついでに、嬉しい副産物がありました。
doctest を実行すると、その数や内容に対して理不尽なほど重いという問題がありました。
参考:
minerva.mamansoft.net
私のコードの場合 doctest 用のコード片が20個ほどあった (いずれも大したことのない内容で、通常の test の方が100倍以上重いものです) のですが、すべて実行するのに5分程度かかっていました。
今回の一時フォルダのパスを書き換える操作を行ったところ、なんと7秒ぐらいで終わるようになりました!(というかこうでないと困るのですが・・・)
なぜフォルダを切り替えただけでまともな時間になったのか、セキュリティソフトが問題だったのか他の何かなのかは不明ですが、小一時間ググっても解決策が出てこなかった問題が突然解決したので、お困りの方はお試しください(何か問題が起きても責任は取れないので自己責任で・・・)。

おまけ

VSCode の tasks.json には以下のように設定しました:

{
    "version": "2.0.0",
    "tasks": [
        // 中略
        {
            "type": "shell",
            "command": "$env:TMP=$env:TEMP_NO_SECURITY; cargo test --release",
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": false
            },
            "label": "rust: cargo test release full (bypass security check)"
        }
    ]
}

*1:$env:***=*** という構文はそのプロセスでのみ一時的に環境変数を書き換えるコマンドなので、テストが終わったら PowerShell のプロセスを終了させるのであれば最後の戻し作業は不要です。