From: Brian Candler Date: 2007-05-04T05:00:13+09:00 Subject: Re: Testing Thread and sleep On Fri, May 04, 2007 at 01:11:39AM +0900, John Miller wrote: > Brian Candler wrote: > > On Thu, May 03, 2007 at 11:54:37AM +0900, John Miller wrote: > >> either. > > I suggest you post your code; modify it so the process it calls via > > popen is > > "sleep 15" or something like that. > > > > I've never had problems testing threads; but I *have* had problems when > > testing code which forks another process (which may include popen). > > > > The problem was that the child process inherited all the Test::Unit > > stuff, > > including its atexit handler. I think the solution was to call exit! at > > the > > end of the child, but I can't remember exactly. > > Actually popen is easy to get around. I rewrote it for the test simply > return a StringIO like object instead of a new process. I can test the > process that is called separately. > > Per request here is the code in question > > This is the method I'm testing: > > #Attempt to kill the process 'pid' after > #'time' seconds. > def terminate_process_after(pid,time) > Thread.new do > sleep time > begin > cross_platform_end_process(pid) > rescue > end > end > end Hmm, that's not what I meant. I meant the full code, complete with test, so it could be run and seen to fail. It's hard for me to replicate exactly what you're talking about, since IO.popen doesn't return a pid. But writing an example using fork and exec works perfectly for me - see below. And as you can see, it uses a thread in just the way you seem to be. Regards, Brian. --- 8< ------------------------------------------------------------------ require 'test/unit' class Foo def terminate_process_after(pid,time) Thread.new do sleep time Process.kill 'TERM', pid end end def doit(cmd) fork { exec(cmd) } # returns pid end end class TestFoo < Test::Unit::TestCase def setup @foo = Foo.new end def test_single pid = @foo.doit("sleep 4") Process.waitpid(pid) end def test_short pid = @foo.doit("sleep 4") @foo.terminate_process_after(pid, 2) Process.waitpid(pid) end def test_long pid = @foo.doit("sleep 4") @foo.terminate_process_after(pid, 6) Process.waitpid(pid) end end