Persimmonはユニットテストを分散実行する夢をみるか?

  1. みるかもしれない。

どういうこと?

かいつまんで問題を説明すると

という話。

今回採用したもの: 案1

コードというか題材というか

https://github.com/persimmon-projects/Persimmon.Ripe/tree/fee25ceabae567cb21e110fe2df2b4f07b72286c

テストオブジェクトのシリアライズ、assemblyロード

別サーバでテストを実行するためには、テストオブジェクトに関連するassemblyをロードする必要がある。 仮にロードしないでテストを実行した場合は例外投げてテストに失敗する。

しかしどうやってロードするかね、という話の段階でVagabondの出番となる。

https://github.com/nessos/Vagabond

このライブラリはリモート環境でAssemblyをロードしたり色々できる優れものである。 また、通信することを想定してFsPicklerというシリアライザ*1を用いてオブジェクトをシリアライズする。

現時点でのPersimmn.Ripeは、Vagabondを使ってAssemblyやテストをRabbitMQ越しにやり取りするライブラリを提供している。

  1. 入力のdll群をロードしてテストオブジェクト一覧を取得する
    • ここまでは通常のPersimmonと同じ
  2. テストオブジェクトに関連するAssemblyをVagabondで取得、RabbitMQに投げる
    • サーバ側はテキトーに受け取ってAssemblyをロードする
  3. テストオブジェクトをシリアライズしてRabbitMQに投げる
    • インターフェースだとキャストに失敗して原因もよくわからなかったのでTextWriter -> objでやり取りしてる…
    • TextWriterを渡す理由は実行したテスト名を出力したいから
  4. 各サーバがメッセージをconsumeしてテスト実行、結果をRabbitMQに投げる
    • 失敗したらエラーをメッセージとしてなげる
  5. 全体統括者がテスト結果を収集して、全部取得できたら結果表示
    • エラーだったら規定回数リトライ、それでもダメなら自分で実行するとかもやってる

この方式のキモ

  • Vagabondが行っているAssemblyの解析とロード
  • FsPicklerが行っている、IL Emitを前提としたシリアライズ

この二つのようなことができれば他の中間言語を持つやつでもわりとなんとかできそう。

課題

Vagabondが対応できる範囲でしか実行できない。 実際、RabbitMQではなくAzure Service Busに切り替えて試してみようとしたところ、VagabondがAssemblyをロードできず死ぬという現象が発生した。

案2を採用しなかった理由

  • コンパイルする環境整えるのつらくない?
  • 全体統括者がWorkerとなるサーバ群を知らないといけないとかそこそこ面倒
  • プロジェクトファイルのsyncだけでリソースもってかれそう

今後の予定とか

  • VagabondでロードできるAssemblyを増やせないか試す
  • AMQP以外のものにも対応させる
    • 例えばアクターとか
  • ちょっと気になっているRubyのtest_queueさんについて調べる
  • Scalaで似たようなことができないか考える

*1:こっちもnessos製