Форкинг подпроцессов в модульных тестах Perl останавливается доказать; Тест:: Жгут выхода
Я пытался использовать утилиту / модуль Perl "proof" в качестве тестового набора для некоторых модульных тестов. Модульные тесты являются немного более "системными", чем "модульными", так как мне нужно отключить некоторые фоновые процессы как часть теста, используя следующее...
sub SpinupMonitor{
my $base_dir = shift;
my $config = shift;
my $pid = fork();
if($pid){
return $pid;
}else{
my $cmd = "$base_dir\/..\/bin\/monitor_real.pl -config $config -test";
close STDOUT;
exec ($cmd) or die "cannot exec test code [$cmd]\n";
}
}
sub KillMonitor{
my $pid = shift;
print "Killing monitor [$pid]\n";
kill(1,$pid);
}
Однако по какой-то причине, когда мой файл.t ускоряет некоторые дополнительные процессы, это приводит к зависанию жгута проводов в конце первого файла.t после завершения всех тестов, вместо перехода к следующему файлу или выхода если есть только один.
Сначала я задавался вопросом, может ли это быть потому, что я убивал свои подпроцессы и оставлял их несуществующими. Итак, я добавил..
$SIG{CHLD} = \&REAPER;
sub REAPER {
my $pid = wait;
$SIG{CHLD} = \&REAPER;
}
К коду. Но это не помогает. Фактически, при закрытом рассмотрении выясняется, что мой тестовый файл perl завершился и теперь является несуществующим процессом, и это сценарий проверки оболочки, который не получил своего потомка. Фактически, когда я добавил вызов die() в конце моего тестового скрипта, я получил...
# Looks like your test died just after 7.
Так что мой сценарий вышел, но по какой-то причине жгут не разваливается.
Я подтвердил, что это определенно мои подпроцессы, которые расстраивают его, как когда я их отключил, в то время как тесты не прошли, выход из жгута проводился правильно.
Есть ли что-то, что я делаю неправильно с тем, как я запускаю свои процессы, которые могут каким-то образом расстроить жгут?
Спасибо
Питер
2 ответа
Я предполагаю, что все ваши дети вышли, прежде чем вы оставите свой тест? Потому что в противном случае, это может зависеть от STDERR, что может запутать доказательство. Если вы можете закрыть STDERR или, по крайней мере, перенаправить на канал в родительском процессе, это может быть одной из ваших проблем.
Кроме того, я бы также отметил, что вам не нужно избегать косой черты, и если вы не используете метасимволы оболочки (пробелы не являются метасимволами для perl - подумайте "*?{}()
"), вы должны быть явными и создать список:
use File::Spec;
my @cmd = File::Spec->catfile($basedir,
File::Spec->updir(),
qw(bin monitor_real.pl)
),
-config => $config,
-test =>;
close STDOUT;
close STDERR;
exec (@cmd) or die "cannot exec test code [@cmd]\n";
Обратите внимание, что вы не проверяете, fork()
не удалось. Вы должны убедиться, $pid
определяется, прежде чем предположить, что "ложь" означает "ребенок".
Потому что ваш $cmd
содержит метасимволы (пробелы) оболочки, Perl фактически использует оболочку при вызове exec()
, Пока ваш монитор работает, есть (1) Perl, (2) ребенок sh -c
и (3) бегающий внуком Perl monitor_real.pl
, Что это означает, в частности, когда вы звоните KillMonitor
вы убиваете только оболочку (потому что это ваш PID), а не монитор.
Вы также можете быть заинтересованы в том, как я разветвляюсь процесс демона? из Perl FAQ.