Automatically detect the usage of parallel tests and modify setup
colszowka opened this issue · 13 comments
See #61: For parallel_tests, it is neccessary to set the command name to something random like this SimpleCov.command_name "RSpec #{rand(100000)}"
so parallel runs do not overwrite each other.
This is not obvious to users of the library and should be handled by SimpleCov automatically.
As a bonus, it would be great if instead of random numbers, some replicable ID would be available for each parallel test run, for example using a MD5 of the invoked shell command so that reported line hits do not add up along the way when the same test runs twice.
Hi,
Where should I put this command_name in the specs for it to work? Immediately after the .start command in spec_helper?
It seems to be generating the coverage in between the split processes, and not merging.
All good, added it to a before each as follows:
config.before(:each) do
SimpleCov.command_name "RSpec:#{Process.pid.to_s}#{ENV['TEST_ENV_NUMBER']}"
end
Hi cesar, it should be placed in your spec_helper, in between your RSpec.configure block.
On 17/03/2012, at 7:36 AM, César Camachoreply@reply.github.com wrote:
All good, added it to a before each as follows:
config.before(:each) do
SimpleCov.command_name "RSpec:#{Process.pid.to_s}#{ENV['TEST_ENV_NUMBER']}"
endWhere should this block of code be placed? Thanks!
Reply to this email directly or view it on GitHub:
#64 (comment)
My original question was where this code block should be placed? I apologize for deleting it. Thanks for the super quick response tommeier!
config.before(:each) do
SimpleCov.command_name "RSpec:#{Process.pid.to_s}#{ENV['TEST_ENV_NUMBER']}"
end
I've actually gone with a less 'brick to the face' method for it, now i've split up tasks, such as unit tests, etc by rake tasks. Then I have a Jenkins CI box that parallelizes out the tasks individually. Adding this to the Rakefile:
Rake::Task.class_eval do
#Required to ensure SimpleCov doesn't overwrite coverage shared values
alias :execute_without_simplecov_command :execute
def execute_and_set_simplecov_command args=nil
ENV['COV_COMMAND'] = "rspec:#{name}" if ENV['COVERAGE']
execute_without_simplecov_command(args)
end
alias :execute :execute_and_set_simplecov_command
end
So simplecov only groups and applies coverage based on the rake task groups, ie: where the custom split has been applied for rake tasks.
Jenkins CI can then merge all these together (from a shared dir). Currently finding it as a very accurate method to merge parallelised specs with SimpleCov.
For RSpec, I'm using
config.before(:each) { SimpleCov.command_name example.location }
to tag the coverage with a unique id per spec (namely the filename and line number, eg ./spec/models/something_spec.rb:123
)
How do you fail the build then? Here's what I do:
# spec/support/coverage.rb
if ENV['COV']
puts "Running with test coverage"
require 'simplecov'
SimpleCov.start 'rails' do
add_filter "lib/extensions"
# bug: changing the coverage_dir here breaks coverage recording.
at_exit do
SimpleCov.result.format!
threshold, actual = 97, SimpleCov.result.covered_percent
if actual < threshold
$stderr.puts "Coverage #{actual}% is below the threshold of #{threshold}%."
exit 1
end
end
end
RSpec.configure do |config|
config.before(:each) do
SimpleCov.command_name "RSpec:#{Process.pid}#{ENV['TEST_ENV_NUMBER']}"
end
end
end
But unfortunately the results don't seem to be merged:
Coverage report generated for RSpec:711845, RSpec:711926, RSpec:711942, RSpec:711977 to proj/x/coverage. 2997 / 3817 LOC (78.52%) covered.
/Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse': 757: unexpected token at '' (MultiJson::DecodeError)
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json/adapters/json_common.rb:7:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json.rb:93:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:20:in `resultset'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:72:in `store_result'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov.rb:48:in `result'
from /Users/dnagir/proj/x/spec/support/coverage.rb:11:in `block (2 levels) in <top (required)>'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `call'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `block in <top (required)>'
/Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse': 757: unexpected token at '' (MultiJson::DecodeError)
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json/adapters/json_common.rb:7:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json.rb:93:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:20:in `resultset'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:44:in `results'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:61:in `merged_result'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov.rb:49:in `result'
from /Users/dnagir/proj/x/spec/support/coverage.rb:10:in `block (2 levels) in <top (required)>'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `call'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `block in <top (required)>'
/Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse': 757: unexpected token at '' (MultiJson::DecodeError)
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json/adapters/json_common.rb:7:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json.rb:93:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:20:in `resultset'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:44:in `results'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:61:in `merged_result'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov.rb:49:in `result'
from /Users/dnagir/proj/x/spec/support/coverage.rb:10:in `block (2 levels) in <top (required)>'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `call'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `block in <top (required)>'
Coverage report generated for RSpec:711845, RSpec:711904, RSpec:711926, RSpec:711942, RSpec:711977 to /Users/dnagir/proj/x/coverage. 3349 / 3817 LOC (87.74%) covered.
/Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse': 757: unexpected token at '' (MultiJson::DecodeError)
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/json-1.7.4/lib/json/common.rb:155:in `parse'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json/adapters/json_common.rb:7:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/multi_json-1.3.6/lib/multi_json.rb:93:in `load'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:20:in `resultset'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/result_merger.rb:72:in `store_result'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov.rb:48:in `result'
from /Users/dnagir/proj/x/spec/support/coverage.rb:11:in `block (2 levels) in <top (required)>'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `call'
from /Users/dnagir/.rvm/gems/ruby-1.9.3-p194/gems/simplecov-0.6.4/lib/simplecov/defaults.rb:51:in `block in <top (required)>'
I'm probably missing something, but not sure what exactly.
Because after running this a few times I started encountering issues with it building the coverage report. I figured out that deleting the coverage folder would get it working again. So for now I've added:
config.before(:suite) do
rm -rf #{Rails.root}/coverage
end
@dnagir you are seeing the same race condition that I'm seeing. Simplecov needs to lock the data file when it accesses it. I'm assuming in lib/simplecov/json.rb
Scratch that json.rb is the wrong place. I'm too tired to hunt it down right now.
It needs to be in lib/simplecov/result_merger.rb and maybe some other places.
PR #185 should totally fix this issue.
As @jshraibman-mdsol wrote an (embarassing) while ago, PR #185 should have fixed this problem. It will be released in a couple of minutes as part of version 0.8.0.pre2