Стекирование подпроцессов в модульных тестах Perl доказывает; Тест:: Проводка, выходящая
Я пытаюсь использовать служебную программу/модуль Perl "доказать" в качестве тестового жгута для некоторых модульных тестов. Модульные тесты - это немного более "система", чем "единица", поскольку мне нужно отбросить некоторые фоновые процессы как часть теста, используя следующее...
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 вышел из строя и теперь является несуществующим процессом, и это завершающая оболочка script, которая не получила своего ребенка. Фактически, когда я добавил вызов die() в конце моего теста script, я получил...
# Looks like your test died just after 7.
Итак, мой script вышел, но по какой-то причине жгут не распутывается.
Я действительно подтвердил, что это, безусловно, мои подпроцессы, которые его нарушают, когда я отключил их, пока тесты не удалили надлежащую проводку.
Есть ли что-то, что я делаю неправильно с тем, как я запускаю свои процессы, которые могут каким-то образом нарушить упряжь?
Спасибо
Петр
Ответы
Ответ 1
Я предполагаю, что все ваши дети вышли, прежде чем покинуть свой тест? Потому что в противном случае он может быть висел на 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";
Ответ 2
Обратите внимание, что вы не проверяете, не удалось ли fork()
. Вы должны убедиться, что $pid
defined, прежде чем считать, что "false" означает "ребенок".
Поскольку ваш $cmd
содержит метасимволы (пробелы) оболочки, Perl на самом деле использует оболочку при вызове exec()
. Пока ваш монитор работает, есть (1) Perl, (2) ребенок sh -c
и (3) внук Perl работает monitor_real.pl
. Это означает, в частности, когда вы вызываете KillMonitor
, вы только убиваете оболочку (потому что у вас есть PID), а не монитор.
Вы также можете быть заинтересованы в Как переделать процесс демона? из FAQ по Perl.