| One of the newly introduced tests in 'pidlock_spec.rb' was being influenced by other tests from 'agent_spec.rb' (if they were run before it). This order dependency issue was solved by making sure that all the tests in 'pidlock_spec.rb' are fully mocked (since before there were expectations based on real executions of a command). As this situation can occur again in the future so these problematic tests from 'agent_spec.rb' need to be checked and revamped accordingly:
- should exit with 1 if an exception is raised
- should exit child process if child exit
- should run the agent in a forked process
- should return the block exit code as the child exit code
The story behind is mostly about a fork mechanism, which is covered by the mentioned tests. This ends up making changes to the rspec's process argument instead of doing the intended action of creating a child process and do said modification to it (not the parent process). The method referred to can be seen in 'agent.rb' as follows:
def run_in_fork(forking = true) |
return yield unless forking or Puppet.features.windows? |
|
atForkHandler = Puppet::Util::AtFork.get_handler |
|
atForkHandler.prepare |
|
begin |
child_pid = Kernel.fork do |
atForkHandler.child |
$0 = _("puppet agent: applying configuration") # <-- Here the child process args are changed |
begin |
exit(yield) |
rescue SystemExit |
exit(-1) |
rescue NoMemoryError |
exit(-2) |
end |
end |
ensure |
atForkHandler.parent |
end |
|
exit_code = Process.waitpid2(child_pid) |
case exit_code[1].exitstatus |
when -1 |
raise SystemExit |
when -2 |
raise NoMemoryError |
end |
exit_code[1].exitstatus |
end
|
An additional interesting finding here (might not be relevant, but seems worth mentioning) was that both 'comm' and 'args' columns of 'ps' show the same information ('puppet agent: applying configuration') when this modification takes place on MacOSX (for any process). Did a quick check on a RedHat 7 VM and there it seems to run as expected (changing only args). This can be easily reproduced by running following ruby script:
#Get current process pid |
pid = Process.pid |
|
before = `ps -p #\{pid\} -o comm,args` |
puts("comm and args before:\n" + before + "\n") |
|
#Change args |
$0 = 'changed' |
|
after = `ps -p #\{pid\} -o comm,args` |
puts("comm and args after\n" + after)
|
This was important for our case solved in 'pidlock_spec.rb' since the command name and it's arguments are checked when deciding whether to unlock or not a stale pidfile in 'pidlock.rb'. The valid cases are either having a process which contains 'ruby' and any arguments containing the word 'puppet' or just a process name ending with the word 'puppet'. Since on MacOSX the process name did not fall under any of the valid cases, the faulty test obviously failed, while on Linux passed. |