Стекирование подпроцессов в модульных тестах 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.