Разветвление подпроцессов в модульных тестах Perl прекращает доказывать;Тест:: Выход жгута проводов
-
06-07-2019 - |
Вопрос
Я пытался использовать утилиту Perl / модуль "prove" в качестве тестового набора для некоторых модульных тестов.Модульные тесты немного более "системные", чем "модульные", поскольку мне нужно отключить некоторые фоновые процессы как часть теста, используя следующее...
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 завершился и теперь является несуществующим процессом, и это скрипт-оболочка prove, который не извлек своего дочернего элемента.На самом деле, когда я добавил вызов die() в конце моего тестового скрипта, я получил...
# Looks like your test died just after 7.
Итак, мой сценарий завершен, но по какой-то причине жгут не распутывается.
Я подтвердил, что это определенно мои подпроцессы, которые расстраивают это, поскольку, когда я отключил их во время неудачных тестов, жгут вышел должным образом.
Есть ли что-то, что я делаю неправильно в том, как я запускаю свои процессы, что может каким-то образом нарушить работу ремня безопасности?
Спасибо
Питер
Решение
Я предполагаю, что все ваши дети закончили обучение до того, как вы закончили свой тест?Потому что в противном случае он может зависнуть на STDERR, что может сбить с толку prove.Если бы вы могли закрыть 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.