14

我一直在尝试使用 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 测试文件已经退出,现在是一个已失效的进程,它是证明包装脚本没有收获它的孩子。事实上,当我在测试脚本末尾添加 die() 调用时,我得到了......

# Looks like your test died just after 7.

所以我的脚本退出了,但由于某种原因,线束没有解开。

我确实确认,当我在测试失败时禁用它们时,肯定是我的子流程让它感到不安,而线束正确退出。

我在启动流程的方式上是否做错了什么,可能会以某种方式扰乱安全带?

4

2 回答 2

12

请注意,您不测试是否fork()失败。在假设“false”表示“child”之前, 您需要确保$pid定义。

因为您$cmd包含 shell 元字符(空格),所以当您调用exec(). 当您的监视器正在运行时,有 (1) Perl、(2) 一个 childsh -c和 (3) 一个孙子 Perl running monitor_real.pl。这尤其意味着当您调用 时KillMonitor,您只是在杀死 shell(因为那是您拥有的 PID)而不是监视器。

您可能还对如何分叉守护进程感兴趣?来自 Perl 常见问题解答。

于 2008-10-08T16:32:44.983 回答
8

我假设你所有的孩子在你离开考试之前都已经退出了?因为否则,它可能会挂在 STDERR 上,这可能会混淆证明。如果您可以关闭 STDERR,或者至少重定向到父进程中的管道,那可能是您遇到的一个问题。

除此之外,我还要指出你不需要转义正斜杠,如果你没有使用 shell 元字符(空格不是 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";
于 2008-10-08T21:07:23.947 回答