Форкинг подпроцессов в модульных тестах Perl останавливается; Тест :: Жгут выхода - PullRequest
13 голосов
/ 08 октября 2008

Я пытался использовать утилиту / модуль 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.

Так что мой сценарий завершился, но по какой-то причине жгут не развалился.

Я подтвердил, что это определенно мои подпроцессы, которые расстраивают его, как когда я их отключил, когда тесты не пройдены, выходной жгут правильно вышел.

Есть ли что-то, что я делаю неправильно с тем, как я запускаю свои процессы, которые могут каким-то образом расстроить жгут?

Спасибо

Peter

Ответы [ 2 ]

12 голосов
/ 08 октября 2008

Обратите внимание, что вы не проверяете, не удалось ли fork(). Вы должны убедиться, что $pid является определенным , прежде чем допустить, что «false» означает «ребенок».

Поскольку ваш $cmd содержит метасимволы (пробелы) оболочки, Perl фактически использует оболочку, когда вы вызываете exec(). Пока ваш монитор работает, есть (1) Perl, (2) дочерний элемент sh -c и (3) внук Perl, работающий monitor_real.pl. В частности, это означает, что когда вы звоните KillMonitor, вы убиваете только оболочку (потому что это ваш PID), а не монитор.

Возможно, вас также заинтересует Как мне развить процесс демона? из FAQ по Perl.

8 голосов
/ 09 октября 2008

Я предполагаю, что все ваши дети вышли из программы до того, как вы ушли с теста? Потому что в противном случае, это может зависеть от 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";
...