Skip to content

Commit

Permalink
Allow ActiveSupport's isolation tests to run with MiniTest on 1.9
Browse files Browse the repository at this point in the history
  • Loading branch information
Carl Lerche committed Dec 31, 2009
1 parent 1fbd02e commit d39d7f5
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 141 deletions.
64 changes: 46 additions & 18 deletions activesupport/lib/active_support/testing/isolation.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -36,28 +36,56 @@ def self.forking_env?
!ENV["NO_FORK"] && RUBY_PLATFORM !~ /mswin|mingw|java/ !ENV["NO_FORK"] && RUBY_PLATFORM !~ /mswin|mingw|java/
end end


def run(result) def self.included(base)
unless defined?(@@ran_class_setup) if defined?(::MiniTest) && base < ::MiniTest::Unit::TestCase
self.class.setup if self.class.respond_to?(:setup) base.send :include, MiniTest
@@ran_class_setup = true elsif defined?(Test::Unit)
base.send :include, TestUnit
end end
end

module TestUnit
def run(result)
unless defined?(@@ran_class_setup)
self.class.setup if self.class.respond_to?(:setup)
@@ran_class_setup = true
end


yield(Test::Unit::TestCase::STARTED, name) yield(Test::Unit::TestCase::STARTED, name)


@_result = result @_result = result


serialized = run_in_isolation do |proxy| serialized = run_in_isolation do |proxy|
begin begin
super(proxy) { } super(proxy) { }
rescue Exception => e rescue Exception => e
proxy.add_error(Test::Unit::Error.new(name, e)) proxy.add_error(Test::Unit::Error.new(name, e))
end
end end

retval, proxy = Marshal.load(serialized)
proxy.__replay__(@_result)

yield(Test::Unit::TestCase::FINISHED, name)
retval
end end
end


proxy = Marshal.load(serialized) module MiniTest
proxy.__replay__(@_result) def run(runner)
unless defined?(@@ran_class_setup)
self.class.setup if self.class.respond_to?(:setup)
@@ran_class_setup = true
end


yield(Test::Unit::TestCase::FINISHED, name) serialized = run_in_isolation do |runner|
super(runner)
end

retval, proxy = Marshal.load(serialized)
proxy.__replay__(runner)
retval
end
end end


module Forking module Forking
Expand All @@ -67,8 +95,8 @@ def run_in_isolation(&blk)
pid = fork do pid = fork do
read.close read.close
proxy = ProxyTestResult.new proxy = ProxyTestResult.new
yield proxy retval = yield proxy
write.puts [Marshal.dump(proxy)].pack("m") write.puts [Marshal.dump([retval, proxy])].pack("m")
exit! exit!
end end


Expand All @@ -87,9 +115,9 @@ def run_in_isolation(&blk)


if ENV["ISOLATION_TEST"] if ENV["ISOLATION_TEST"]
proxy = ProxyTestResult.new proxy = ProxyTestResult.new
yield proxy retval = yield proxy
File.open(ENV["ISOLATION_OUTPUT"], "w") do |file| File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
file.puts [Marshal.dump(proxy)].pack("m") file.puts [Marshal.dump([retval, proxy])].pack("m")
end end
exit! exit!
else else
Expand Down
266 changes: 143 additions & 123 deletions activesupport/test/isolation_test.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,162 +1,182 @@
require 'abstract_unit' require 'abstract_unit'
require 'rbconfig' require 'rbconfig'


if defined?(MiniTest) || defined?(Test::Unit::TestResultFailureSupport) # if defined?(MiniTest) || defined?(Test::Unit::TestResultFailureSupport)
$stderr.puts "Isolation tests can test test-unit 1 only" # $stderr.puts "Isolation tests can test test-unit 1 only"


else if ENV['CHILD']
# Does awesome class ChildIsolationTest < ActiveSupport::TestCase
if ENV['CHILD'] include ActiveSupport::Testing::Isolation
class ChildIsolationTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation

def self.setup
File.open(File.join(File.dirname(__FILE__), "fixtures", "isolation_test"), "a") do |f|
f.puts "hello"
end
end


def setup def self.setup
@instance = "HELLO" File.open(File.join(File.dirname(__FILE__), "fixtures", "isolation_test"), "a") do |f|
f.puts "hello"
end end
end


def teardown def setup
raise if @boom @instance = "HELLO"
end end


test "runs the test" do def teardown
assert true raise if @boom
end end


test "captures errors" do test "runs the test" do
raise assert true
end end


test "captures failures" do test "captures errors" do
assert false raise
end end


test "first runs in isolation" do test "captures failures" do
assert_nil $x assert false
$x = 1 end
end


test "second runs in isolation" do test "first runs in isolation" do
assert_nil $x assert_nil $x
$x = 2 $x = 1
end end


test "runs with slow tests" do test "second runs in isolation" do
sleep 0.3 assert_nil $x
assert true $x = 2
sleep 0.2 end
end


test "runs setup" do test "runs with slow tests" do
assert "HELLO", @instance sleep 0.3
end assert true
sleep 0.2
end


test "runs teardown" do test "runs setup" do
@boom = true assert "HELLO", @instance
end end


test "resets requires one" do test "runs teardown" do
assert !defined?(OmgOmg) @boom = true
assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size end
require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg"))
end


test "resets requires two" do test "resets requires one" do
assert !defined?(OmgOmg) assert !defined?(OmgOmg)
assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size
require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg")) require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg"))
end
end end
else
class ParentIsolationTest < ActiveSupport::TestCase

File.open(File.join(File.dirname(__FILE__), "fixtures", "isolation_test"), "w") {}

ENV["CHILD"] = "1"
OUTPUT = `#{RbConfig::CONFIG["bindir"]}/#{RbConfig::CONFIG["ruby_install_name"]} -I#{File.dirname(__FILE__)} "#{File.expand_path(__FILE__)}" -v`
ENV.delete("CHILD")

def setup
# Extract the results
@results = {}
OUTPUT[/Started\n\s*(.*)\s*\nFinished/mi, 1].to_s.split(/\s*\n\s*/).each do |result|
result =~ %r'^(\w+)\(\w+\):\s*(\.|E|F)$'
@results[$1] = { 'E' => :error, '.' => :success, 'F' => :failure }[$2]
end

# Extract the backtraces
@backtraces = {}
OUTPUT.scan(/^\s*\d+\).*?\n\n/m).each do |backtrace|
# \n 1) Error:\ntest_captures_errors(ChildIsolationTest):
backtrace =~ %r'\s*\d+\)\s*(Error|Failure):\n(\w+)'i
@backtraces[$2] = { :type => $1, :output => backtrace }
end
end


def assert_failing(name) test "resets requires two" do
assert_equal :failure, @results[name.to_s], "Test #{name} did not fail" assert !defined?(OmgOmg)
end assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size
require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg"))
end
end
else
class ParentIsolationTest < ActiveSupport::TestCase


def assert_passing(name) File.open(File.join(File.dirname(__FILE__), "fixtures", "isolation_test"), "w") {}
assert_equal :success, @results[name.to_s], "Test #{name} did not pass"
end


def assert_erroring(name) ENV["CHILD"] = "1"
assert_equal :error, @results[name.to_s], "Test #{name} did not error" OUTPUT = `#{RbConfig::CONFIG["bindir"]}/#{RbConfig::CONFIG["ruby_install_name"]} -I#{File.dirname(__FILE__)} "#{File.expand_path(__FILE__)}" -v`
end ENV.delete("CHILD")


test "has all tests" do def setup
assert_equal 10, @results.length defined?(::MiniTest) ? parse_minitest : parse_testunit
end end


test "passing tests are still reported" do def parse_testunit
assert_passing :test_runs_the_test @results = {}
assert_passing :test_runs_with_slow_tests OUTPUT[/Started\n\s*(.*)\s*\nFinished/mi, 1].to_s.split(/\s*\n\s*/).each do |result|
result =~ %r'^(\w+)\(\w+\):\s*(\.|E|F)$'
@results[$1] = { 'E' => :error, '.' => :success, 'F' => :failure }[$2]
end end


test "resets global variables" do # Extract the backtraces
assert_passing :test_first_runs_in_isolation @backtraces = {}
assert_passing :test_second_runs_in_isolation OUTPUT.scan(/^\s*\d+\).*?\n\n/m).each do |backtrace|
# \n 1) Error:\ntest_captures_errors(ChildIsolationTest):
backtrace =~ %r'\s*\d+\)\s*(Error|Failure):\n(\w+)'i
@backtraces[$2] = { :type => $1, :output => backtrace }
end end
end


test "resets requires" do def parse_minitest
assert_passing :test_resets_requires_one @results = {}
assert_passing :test_resets_requires_two OUTPUT[/Started\n\s*(.*)\s*\nFinished/mi, 1].to_s.split(/\s*\n\s*/).each do |result|
end result =~ %r'^\w+#(\w+):.*:\s*(.*Assertion.*|.*RuntimeError.*|\.\s*)$'
val = :success
val = :error if $2.include?('RuntimeError')
val = :failure if $2.include?('Assertion')


test "erroring tests are still reported" do @results[$1] = val
assert_erroring :test_captures_errors
end end


test "runs setup and teardown methods" do # Extract the backtraces
assert_passing :test_runs_setup @backtraces = {}
assert_erroring :test_runs_teardown OUTPUT.scan(/^\s*\d+\).*?\n\n/m).each do |backtrace|
# \n 1) Error:\ntest_captures_errors(ChildIsolationTest):
backtrace =~ %r'\s*\d+\)\s*(Error|Failure):\n(\w+)'i
@backtraces[$2] = { :type => $1, :output => backtrace }
end end
end


test "correct tests fail" do def assert_failing(name)
assert_failing :test_captures_failures assert_equal :failure, @results[name.to_s], "Test #{name} failed"
end end


test "backtrace is printed for errors" do def assert_passing(name)
assert_equal 'Error', @backtraces["test_captures_errors"][:type] assert_equal :success, @results[name.to_s], "Test #{name} passed"
assert_match %r{isolation_test.rb:\d+:in `test_captures_errors'}, @backtraces["test_captures_errors"][:output] end
end


test "backtrace is printed for failures" do def assert_erroring(name)
assert_equal 'Failure', @backtraces["test_captures_failures"][:type] assert_equal :error, @results[name.to_s], "Test #{name} errored"
assert_match %r{isolation_test.rb:\d+:in `test_captures_failures'}, @backtraces["test_captures_failures"][:output] end
end


test "self.setup is run only once" do test "has all tests" do
text = File.read(File.join(File.dirname(__FILE__), "fixtures", "isolation_test")) assert_equal 10, @results.length
assert_equal "hello\n", text end
end
test "passing tests are still reported" do
assert_passing :test_runs_the_test
assert_passing :test_runs_with_slow_tests
end


test "resets global variables" do
assert_passing :test_first_runs_in_isolation
assert_passing :test_second_runs_in_isolation
end end

test "resets requires" do
assert_passing :test_resets_requires_one
assert_passing :test_resets_requires_two
end

test "erroring tests are still reported" do
assert_erroring :test_captures_errors
end

test "runs setup and teardown methods" do
assert_passing :test_runs_setup
assert_erroring :test_runs_teardown
end

test "correct tests fail" do
assert_failing :test_captures_failures
end

test "backtrace is printed for errors" do
assert_equal 'Error', @backtraces["test_captures_errors"][:type]
assert_match %r{isolation_test.rb:\d+}, @backtraces["test_captures_errors"][:output]
end

test "backtrace is printed for failures" do
assert_equal 'Failure', @backtraces["test_captures_failures"][:type]
assert_match %r{isolation_test.rb:\d+}, @backtraces["test_captures_failures"][:output]
end

test "self.setup is run only once" do
text = File.read(File.join(File.dirname(__FILE__), "fixtures", "isolation_test"))
assert_equal "hello\n", text
end

end end
end end

0 comments on commit d39d7f5

Please sign in to comment.