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

Другие вопросы по тегам