[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Testing Thread and sleep

John Miller

5/3/2007 2:55:00 AM

Greetings All:

I'm writing a script that calls an external program using popen. The
program has the potential to run forever, but I what to kill it if it
has not found a solution in 10 seconds. I have therefore set up a
Thread that 'sleep's for 10 seconds and then calls Process.kill on the
PID. I've been successful in mocking out the popen call and Process,
but I am having trouble writing a test that ensures the thread will be
killed. Test::Unit seems to ignore/override threads.

Can anyone give me some advice on how to test threads? It would be
really nice if I didn't have to actually wait the full 10 seconds
either.

John Miller

--
Posted via http://www.ruby-....

5 Answers

Brian Candler

5/3/2007 7:30:00 AM

0

On Thu, May 03, 2007 at 11:54:37AM +0900, John Miller wrote:
> I'm writing a script that calls an external program using popen. The
> program has the potential to run forever, but I what to kill it if it
> has not found a solution in 10 seconds. I have therefore set up a
> Thread that 'sleep's for 10 seconds and then calls Process.kill on the
> PID. I've been successful in mocking out the popen call and Process,
> but I am having trouble writing a test that ensures the thread will be
> killed. Test::Unit seems to ignore/override threads.
>
> Can anyone give me some advice on how to test threads? It would be
> really nice if I didn't have to actually wait the full 10 seconds
> 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.

John Miller

5/3/2007 4:12:00 PM

0

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

John



--
Posted via http://www.ruby-....

Raf Coremans

5/3/2007 7:21:00 PM

0

2007/5/3, John Miller <jfmiller28@yahoo.com>:
> Greetings All:
>
> I'm writing a script that calls an external program using popen. The
> program has the potential to run forever, but I what to kill it if it
> has not found a solution in 10 seconds. I have therefore set up a
> Thread that 'sleep's for 10 seconds and then calls Process.kill on the
> PID. I've been successful in mocking out the popen call and Process,
> but I am having trouble writing a test that ensures the thread will be
> killed. Test::Unit seems to ignore/override threads.
>
> Can anyone give me some advice on how to test threads? It would be
> really nice if I didn't have to actually wait the full 10 seconds
> either.
>
> John Miller
>
> --
> Posted via http://www.ruby-....
>

How about using the timeout module?

require 'timeout'
begin
Timeout::timeout(10) do
#do stuff...
end
rescue Timeout::Error
puts "Cut short"
else
puts "Ran until the end"
end

Regards,
Raf

Brian Candler

5/3/2007 8:00:00 PM

0

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


John Miller

5/4/2007 7:44:00 PM

0

Brian Candler wrote:
> On Fri, May 04, 2007 at 01:11:39AM +0900, John Miller wrote:
>> > The problem was that the child process inherited all the Test::Unit
>>
>> 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.

io = IO.popen('-', 'w+')
pid = io.pid

Note that 'fork' is not supported in windows, only popen.

I believe I have found where my problem was, and a solution. The
problem is that my main process was ending after a couple of seconds
worth of tests with the mocked out process and terminate_process threads
still running. I needed to Thread.join my mock_process thread at the
end of my test.

John Miller

--
Posted via http://www.ruby-....