namespace :docker do | |
desc "Run tasks in parallel using docker" | |
task :test do | |
forks = 4 | |
begin | |
# Start docker containers (serially, docker seems to have problems with concurrency) | |
ports = {} | |
forks.times do |i| | |
# Start redis and get the mapped port | |
`docker run -d -p 6379 -name redis#{i} yourdockeruser/redis` | |
ports["redis#{i}"] = `docker port redis#{i} 6379`.split(":").last.to_i | |
# Start solr and get the mapped port | |
`docker run -d -p 8983 -name solr#{i} yourdockeruser/solr` | |
ports["solr#{i}"] = `docker port solr#{i} 8983`.split(":").last.to_i | |
end | |
# Wait for services in the docker container to start | |
sleep(15) | |
# Randomize which forks get which tests | |
test_files = FileList['test/**/test*.rb'].shuffle | |
# Slice the test files to evenly distribute amongst forks | |
test_files_sliced = test_files.each_slice(test_files.length / forks).to_a | |
pids = [] | |
forks.times do |i| | |
pids << fork do | |
begin | |
## | |
# Configure your environment | |
# You'll want to do something here to make the environment | |
# use the redis_port and solr_port variables from above. | |
# This may be calling something like Rails::Initializer.run(). | |
# You can access the ports by using the ports hash: | |
# config.redis_port = ports["redis#{i}"] | |
# If you use a base test class, require that first | |
require_relative "test/test_case" | |
# Require the test files for this particular fork | |
test_files_sliced[i].each {|f| require_relative f} | |
# redirect stdout | |
require 'stringio' | |
sio = StringIO.new | |
$stdout = sio | |
$stderr = sio | |
# Run the tests | |
MiniTest::Unit.runner.run | |
rescue => e | |
sio << "\n#{e.message}\n#{e.backtrace.join("\t\n")}" | |
ensure | |
# reset stdout | |
$stdout = STDOUT | |
sio.rewind | |
# Output the test results | |
puts "Fork #{i} completed, output:" | |
puts "Testing:\n#{test_files_sliced[i].join(", ")}\n" | |
puts sio.read | |
# Force the fork to end without running at_exit bindings | |
Kernel.exit! | |
end | |
end | |
end | |
# Wait for the forks to finish the tests | |
pids.each {|pid| Process.wait(pid)} | |
rescue Exception => e | |
puts e.message | |
puts e.backtrace.join("\n\t") | |
ensure | |
puts "Stopping docker containers" | |
forks.times {|i| `docker kill redis#{i} && docker rm redis#{i}`} | |
forks.times {|i| `docker kill solr#{i} && docker rm solr#{i}`} | |
Kernel.exit! # force the process to quit without minitest's autorun (triggered on at_exit) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment