HOWTO: Background tasks during test (ugly)

I am writing a script that reads connection information from a config
file, and based, on what it finds, connects to multiple mysql servers
and performs tasks. To test this script, I need to set up test
servers, but getting them running without causing the tests to be
rerun when they stop is a bit…tricky. I cannot say that I’m proud of
it, but here is how I did it:

tc_my_script_spec.rb:
require ‘my_script’

def setup_test_servers
teardown_test_servers(:kill)

pids = []

pid = fork {nohup mysqld_safe --no-defaults #{server_options * ' '} &}
raise “mysqld_safe fork failed” if $? != 0
if pid
pids << pid
else
exit!
end

pids.each{|pid| Process.kill(9,pid)}

Spec::Runner.configure do |config|
config.after(:suite)
at_exit(teardown_test_servers(nil)
end
end
end

def teardown_test_servers(kill)
@servers.each do |server, data|
connection_options = {
:host => data[:host],
:port => data[:port],
:user => ‘shutdown’,
}
connection_string = '–no-defaults ’ + connect_options.map{|opt,
val| “–#{opt}=#{val}”} * ’ ’
if doit_status(“mysqladmin #{connect_string} ping 2>&1”) == 0
doit(“mysqladmin #{connect_string} shutdown”)
end
doit(“rm -rf #{datadir}”) if kill or !File.exists? “#{datadir}/keep”
end

def doit(command)
response = core_do(command)
$? != 0 and raise “Command: #{command}\nExit code :#{’%x’ % $?}.\n#
{response}”
response
end

def doit_status(command)
core_do(command)
$? >> 8
end

def core_do(command)
response = #{command}
signal = $? & 0x7f
kill(signal, 0) if signal != 0
response
end

describe …

On Oct 29, 2009, at 3:09 am, Student wrote:

I am writing a script that reads connection information from a config
file, and based, on what it finds, connects to multiple mysql servers
and performs tasks. To test this script, I need to set up test
servers, but getting them running without causing the tests to be
rerun when they stop is a bit…tricky. I cannot say that I’m proud of
it, but here is how I did it:

Is this because of autospec? If so, you can modify the files autotest
watches. Or, you could do the server stuff in a tmpdir[1] directory.

Let me know if I’m off-target - I can’t see the definition of
datadir in your snippet.

Ashley

[1] Any nice way to get a temporary directory? - Ruby - Ruby-Forum


http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashleymoran

No autoscript here. I don’t doubt that there are wrappers that might
handle it, I was going for a solution in a bare rspec environment.

datadir was missed in the transposition–it should have been data
[:dir].

Nathan

On Oct 29, 5:22 am, Ashley M. [email protected]

On Oct 29, 2009, at 12:28 pm, Student wrote:

No autoscript here. I don’t doubt that there are wrappers that might
handle it, I was going for a solution in a bare rspec environment.

Still not sure I understand the problem. Can you explain what you
mean by “getting them running without causing the tests to be rerun
when they stop is a bit…tricky”? Can you paste output to illustrate
this?

Ashley


http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashleymoran

forever.sh:
while true ; do sleep 5 ; done

tc_forks.rb
2.times do
fork {nohup sh forever.sh &}
end

describe “We can do tests in the air” do

it “Here is the first test” do
1.should not_raise
end
end

spec tc_forks_spec.rb
nohup: redirecting stderr to stdout
nohup: redirecting stderr to stdout
F

NameError in ‘We can do tests in the air Here is the first test’
undefined local variable or method `not_raise’ for
#Spec::Example::ExampleGroup::Subclass_1:0xb7a5005c
./tc_forks_spec.rb:8:

Finished in 0.005975 seconds

1 example, 1 failure
nathan-desktop ~/work/rspec_multiple ps
PID TTY TIME CMD
10637 pts/2 00:00:00 bash
11010 pts/2 00:00:00 nedit
11286 pts/2 00:00:00 spec
11287 pts/2 00:00:00 spec
11288 pts/2 00:00:00 sh
11289 pts/2 00:00:00 sh
11290 pts/2 00:00:00 sh
11291 pts/2 00:00:00 sh
11300 pts/2 00:00:00 sleep
11301 pts/2 00:00:00 sleep
11303 pts/2 00:00:00 ps
nathan-desktop ~/work/rspec_multiple kill 11290
nathan-desktop ~/work/rspec_multiple nohup: redirecting stderr to
stdout
nohup: redirecting stderr to stdout
F

NameError in ‘We can do tests in the air Here is the first test’
undefined local variable or method `not_raise’ for
#Spec::Example::ExampleGroup::Subclass_1:0xb7a4e900
./tc_forks_spec.rb:8:
./tc_forks_spec.rb:2:

Finished in 0.006251 seconds

1 example, 1 failure

nathan-desktop ~/work/rspec_multiple ps
PID TTY TIME CMD
10637 pts/2 00:00:00 bash
11010 pts/2 00:00:01 nedit
11286 pts/2 00:00:00 spec
11288 pts/2 00:00:00 sh
11291 pts/2 00:00:00 sh
11346 pts/2 00:00:00 spec
11347 pts/2 00:00:00 spec
11348 pts/2 00:00:00 sh
11349 pts/2 00:00:00 sh
11350 pts/2 00:00:00 sh
11351 pts/2 00:00:00 sh
11436 pts/2 00:00:00 sleep
11437 pts/2 00:00:00 sleep
11438 pts/2 00:00:00 sleep
11439 pts/2 00:00:00 ps

There are variations here. This particular example spawned two new
spec processes when I killed one of the sh process. I thought it
worthwhile to publish the one that works. :wink:

On Oct 29, 9:54 am, Ashley M. [email protected]

On Oct 29, 2009, at 11:17 AM, Student [email protected]
wrote:

it “Here is the first test” do
1.should not_raise

1.should_not raise_error