Skip to content

Instantly share code, notes, and snippets.

@paukul
Created December 26, 2010 08:52
Show Gist options
  • Save paukul/755304 to your computer and use it in GitHub Desktop.
Save paukul/755304 to your computer and use it in GitHub Desktop.
hydra, deeptest and others were a little heavyweight for my needs
ENV['RAILS_ENV'] = "test"
require 'test/unit/testsuite'
require 'test/unit/collector/objectspace'
require 'test/unit/ui/testrunnermediator'
require 'test/unit/ui/console/testrunner'
require 'test/unit/testresult'
require 'config/environment'
require 'drb'
no_workers = 4
Test::Unit.run = true # avoid running the autorunner
# SafeFork taken from hydra: https://github.com/ngauthier/hydra/blob/master/lib/hydra/safe_fork.rb
class SafeFork
def self.fork
begin
# remove our connection so it doesn't get cloned
connection = ActiveRecord::Base.remove_connection if defined?(ActiveRecord)
# fork a process
child = Process.fork do
begin
# create a new connection and perform the action
begin
ActiveRecord::Base.establish_connection((connection || {}).merge({:allow_concurrency => true})) if defined?(ActiveRecord)
rescue ActiveRecord::AdapterNotSpecified
# AR was defined but we didn't have a connection
end
yield
ensure
# make sure we remove the connection before we're done
ActiveRecord::Base.remove_connection if defined?(ActiveRecord)
end
end
ensure
# make sure we re-establish the connection before returning to the main instance
begin
ActiveRecord::Base.establish_connection((connection || {}).merge({:allow_concurrency => true})) if defined?(ActiveRecord)
rescue ActiveRecord::AdapterNotSpecified
# AR was defined but we didn't have a connection
end
end
return child
end
end
class TestMonitor
def initialize
@runners = 0
@finished_results = []
@faults = []
@first_testrun = nil
end
def next_engine
engines.pop
end
def say(something)
puts something
end
def engines
@engines ||= begin
e = %w(. best_offers core_tools xws)
# e = Dir[File.expand_path('../../engines', __FILE__) + "/*"].map{|f| "engines/" + File.basename(f)}.unshift(".")
@no_engines = e.size
e
end
end
def add_fault(fault)
$stdout.print fault.single_character_display
@faults << fault
# $stdout.flush
# $stdout.puts "\n-----------------------------------------"
# $stdout.puts fault.long_display
# $stdout.puts "-----------------------------------------"
end
def test_finished(name)
$stdout.print "."
$stdout.flush
end
def started
@first_testrun ||= Time.new
@runners += 1
end
def finished(elapsed_time, result)
@runners -= 1
@finished_results << result
# $stdout.puts "DONE in #{elapsed_time}"
if @finished_results.size == @no_engines
report_results
Thread.exit
end
end
def test_started(name)
end
def report_results
@faults.each do |fault|
puts fault.long_display
end
@finished_results.each do |res|
puts res
end
puts "Complete testrun in: #{Time.now - @first_testrun}"
end
end
class MonitoredRunner
include DRbUndumped
attr_reader :result
def initialize(suite, monitor)
@monitor = monitor
@suite = suite
end
def self.run(suite, monitor = TestMonitor.new)
new(suite, monitor).start
end
# Begins the test run.
def start
setup_mediator
attach_to_mediator
@mediator.run_suite
end
private
def setup_mediator
@mediator = create_mediator(@suite)
suite_name = @suite.to_s
if ( @suite.kind_of?(Module) )
suite_name = @suite.name
end
end
def create_mediator(suite)
Test::Unit::UI::TestRunnerMediator.new(suite)
end
def attach_to_mediator
@mediator.add_listener(Test::Unit::TestResult::FAULT, &method(:add_fault))
@mediator.add_listener(Test::Unit::UI::TestRunnerMediator::STARTED, &method(:started))
@mediator.add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED, &method(:finished))
@mediator.add_listener(Test::Unit::TestCase::STARTED, &method(:test_started))
@mediator.add_listener(Test::Unit::TestCase::FINISHED, &method(:test_finished))
end
def add_fault(fault)
@monitor.add_fault(fault)
end
def started(result)
@result = result
@monitor.started
end
def finished(elapsed_time)
@monitor.finished(elapsed_time, @result)
end
def test_started(name)
@monitor.test_started(name)
end
def test_finished(name)
@monitor.test_finished(name)
end
end
DRb.start_service nil, TestMonitor.new
require 'drb/timeridconv'
DRb.install_id_conv(DRb::TimerIdConv.new)
uri = DRb.uri
def fork_me_baby(uri)
SafeFork.fork do
trap("INT") { } #dunno rly...
DRb.start_service
monitor = DRbObject.new nil, uri
$stdout = open("/dev/null", "w")
if e = monitor.next_engine
e = e == "." ? e : "engines/#{e}"
monitor.say "Loading for #{e}"
Dir[File.join(e, "test", "**", "*_test.rb")].each do |f|
load f
end
suite = Test::Unit::Collector::ObjectSpace.new.collect
MonitoredRunner.run(suite, monitor)
fork_me_baby(uri)
end
end
end
no_workers.times { fork_me_baby(uri) }
trap("INT") {
monitor = DRbObject.new nil, uri
monitor.report_results
}
DRb.thread.join
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment