Test::Unit teardown with child process

B

Brian Candler

I have a suggestion which might improve the behaviour of the 'teardown'
facility in Test::Unit.

I had a problem where my tests were being torn down prematurely, which took
some hunting around to find. It turned out that it was because my tests were
forking a child process using IO.popen, and when the child terminated, the
teardown was being called. The test script attached below demonstrates this.

I can work around it like this:

class MyTest < Test::Unit::TestCase

BASEPID = $$

def teardown
# If we are a child process exiting, don't do any teardown
return unless BASEPID == $$

.. do stuff
end
end

But I think it would be nice if the Test::Unit infrastructure could take
care of that, i.e. only call the teardown methods if the current pid is the
same as the pid when the 'setup' method was called.

However, I have to say I don't understand this entirely. If I fork a child
using Process.fork then the child's termination *doesn't* cause the teardown
to be called - see method test2 in the attached script.

Any ideas why test1 and test2 should be different in this regard?

Regards,

Brian.
-------------------------------------------------------------------------
require 'test/unit'

class MyTest < Test::Unit::TestCase

def setup
$stderr.puts "setup #{$$}"
File.open("xxx","w") { |f| f.puts "testdata" }
end

def teardown
$stderr.puts "teardown #{$$}"
File.delete("xxx")
end

# This test fails; teardown is called prematurely

def test1
res = nil
IO.popen("-") do |pipe|
if pipe
res = pipe.read
else
puts "hello"
exit 0
end
end
assert_match(/hello/, res, "child status")

data = nil
File.open("xxx") { |f| data = f.read }
assert_match(/testdata/, data)
end

# Strangely, this test succeeds

def test2
pid = Process.fork do
puts "Child OK #{$$}"
exit 0
end
dummy, status = Process.waitpid2(pid)
assert_equal(pid, dummy, "correct pid")
assert_equal(0, status.exitstatus, "correct exit status")

sleep 1
data = nil
File.open("xxx") { |f| data = f.read }
assert_match(/testdata/, data)
end
end
 
R

Ryan Davis

class MyTest < Test::Unit::TestCase

BASEPID = $$

def teardown
# If we are a child process exiting, don't do any teardown
return unless BASEPID == $$

.. do stuff
end
end

I've been tearing up rubicon in the past couple of days and noticed
something similar that might help you:

def teardown
if $os != MsWin32 && $os != JRuby
begin
loop { Process.wait; $stderr.puts "\n\nCHILD REAPED\n\n" }
rescue Errno::ECHILD
end
end
super
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top