経緯
- RSpec + Capybara を test-queue で動かすぞ!!
- app サーバはローカルで rack で、とかじゃなくて別ホストに立ってるものとする
- いろいろあって全 worker が同じ app サーバを見ると困る
Capybara.app_host
を使えばアクセス先を変更できる- ↑ これを worker 毎に違う値設定できればいいんじゃないかな
同じ app サーバを見せたくないだけなら NginX など使って load balancing すればいいじゃないかみたいなのはとりあえず置いといてください。世界が厳しいのです。
解決方法
README に全てがある
Since test-queue uses fork(2) to spawn off workers, you must ensure each worker runs in an isolated environment. Use the after_fork hook with a custom runner to reset any global state.
つまり TestQueue::Runner::使用するテストフレームワーク
を継承するクラスを作って、
それぞれメソッドがプロセス空間内?で呼び出されるからよしなにやってくれ、というものです。
解決例
今回は Capybara + RSpec
で動く test-queue
環境を作りたいので、TestQueue::Runner::RSpec
を使います。
$ emacs my_app_test_runner
#!/usr/bin/env ruby require 'test_queue/iterator' require 'test_queue/runner/rspec' require 'rspec' class MyAppTestRunner < TestQueue::Runner::RSpec # # num は worker ID (1,2,...) # def after_fork(num) Capybara.app_host = "http://app#{num}.example.com" end end MyAppTestRunner.new.execute
after_fork()
は fork された RSpec プロセス内で呼び出される ので、
このメソッド内で設定した環境変数やグローバル変数はプロセスに閉じます。
続いてこのファイルを rspec-queue
コマンドの代わりに呼び出します。
今回は worker 数を 5 としてみましょう。
# 標準の RSpec ランナーを実行する場合は # bundle exec rspec-queue spec/ $ TEST_QUEUE_WORKERS=5 bundle exec ruby my_app_test_runner spec/
このように実行すると、各 worker はそれぞれ以下の URL に対しアクセスします。
worker[1] = http://app1.example.com
worker[2] = http://app2.example.com
worker[3] = http://app3.example.com
worker[4] = http://app4.example.com
worker[5] = http://app5.example.com
無事 worker が乱れ飛ぶようなテストが走らないようになりました。やったね!
おまけ(RSpec のレポートを worker 毎に出力したい)
test-queue
を使うとテストケース自体は並列に実行されますが、その結果となるレポートの出力先までは複数に別れていません。
というのも fork する前に RSpec.configuration を設定しているから です。
なのでこの場合も after_fork()
内に書く作戦でいきましょう。
#!/usr/bin/env ruby require 'test_queue/iterator' require 'test_queue/runner/rspec' require 'rspec' class MyAppTestRunner < TestQueue::Runner::RSpec def after_fork(num) Capybara.app_host = "http://app#{num}.example.com" # 追加 ::RSpec.configure do |config| config.add_formatter 'html', "report#{num}.html" end end end MyAppTestRunner.new.execute
これで worker 数5 で実行すると、最終的に report1.html
から report5.html
が生成されます。
ちなみに
parallel_tests
の場合は
みたいになるので、.rspec
とか .rspec_parallel
に
-f html -o report<%= ENV['TEST_ENV_NUMBER'] %>.html
という技が使えます。
まとめ
test-queue
便利!