209 lines
3.9 KiB
Perl
209 lines
3.9 KiB
Perl
|
|
package runproduct;
|
|
|
|
=head1 NAME
|
|
|
|
runproduct - Runs and stops either aprsc or javaprssrvr with a selected
|
|
configuration, hiding the application-specific details from the test.
|
|
|
|
=cut
|
|
|
|
use 5.006;
|
|
use strict;
|
|
use warnings;
|
|
use IPC::Open3;
|
|
use POSIX ":sys_wait_h";
|
|
use Data::Dumper;
|
|
|
|
my %products = (
|
|
'aprsc' => {
|
|
'binary' => '../src/aprsc',
|
|
'stdargs' => '-e debug -o file -r logs',
|
|
'cfgfileargs' => '-c',
|
|
'cfgdir' => 'cfg-aprsc'
|
|
},
|
|
'javap' => {
|
|
'binary' => './javaprssrvr/java',
|
|
'stdargs' => '-server -cp ./javaprssrvr/javAPRSSrvr.jar javAPRSSrvr',
|
|
'cfgfileargs' => '',
|
|
'cfgdir' => 'cfg-javap',
|
|
'dieswith' => 15,
|
|
'exitcode' => 143
|
|
}
|
|
);
|
|
|
|
sub new($$)
|
|
{
|
|
my($class, $config) = @_;
|
|
my $self = bless { @_ }, $class;
|
|
|
|
if (defined $ENV{'TEST_PRODUCT'}) {
|
|
$self->{'prod_name'} = $ENV{'TEST_PRODUCT'};
|
|
} else {
|
|
$self->{'prod_name'} = 'aprsc';
|
|
}
|
|
|
|
if (!defined $products{$self->{'prod_name'}}) {
|
|
warn "No such product: " . $self->{'prod_name'} . "\n";
|
|
return undef;
|
|
}
|
|
|
|
my $prod = $self->{'prod'} = $products{$self->{'prod_name'}};
|
|
|
|
my $cfgfile = $self->{'cfgfile'} = $prod->{'cfgdir'} . '/' . $config;
|
|
if (! -f $cfgfile) {
|
|
warn "No such configuration file: $cfgfile";
|
|
return undef;
|
|
}
|
|
|
|
$self->{'cmdline'} = $prod->{'binary'} . ' ' . $prod->{'stdargs'} . ' '
|
|
. $prod->{'cfgfileargs'} . ' ' . $cfgfile;
|
|
|
|
$self->{'error'} = 'No errors yet';
|
|
|
|
return $self;
|
|
}
|
|
|
|
sub readout($)
|
|
{
|
|
my($self) = @_;
|
|
}
|
|
|
|
sub start($)
|
|
{
|
|
my($self) = @_;
|
|
|
|
if (defined $self->{'pid'}) {
|
|
return "Product already running.";
|
|
}
|
|
|
|
#warn "Product command line: $self->{cmdline}\n";
|
|
|
|
my($stdin, $stdout, $stderr);
|
|
my $pid = open3($stdin, $stdout, $stderr, $self->{'cmdline'});
|
|
|
|
if (!defined $pid) {
|
|
return "Failed to run product: $!";
|
|
}
|
|
|
|
# let it start...
|
|
sleep(1);
|
|
|
|
my $kid = waitpid($pid, WNOHANG);
|
|
|
|
if ($kid) {
|
|
my $retval = $?;
|
|
my $signal = $retval & 127;
|
|
$retval = $retval >> 8;
|
|
|
|
$self->readout();
|
|
$self->discard();
|
|
return "Product quit after startup, signal $signal retcode $retval.";
|
|
}
|
|
|
|
$self->{'pid'} = $pid;
|
|
$self->{'stdin'} = $stdin;
|
|
$self->{'stdout'} = $stdout;
|
|
$self->{'stderr'} = $stderr;
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub discard($)
|
|
{
|
|
my($self) = @_;
|
|
|
|
close($self->{'stdin'}) if (defined $self->{'stdin'});
|
|
close($self->{'stdout'}) if (defined $self->{'stdout'});
|
|
close($self->{'stderr'}) if (defined $self->{'stderr'});
|
|
|
|
undef $self->{'stdin'};
|
|
undef $self->{'stdout'};
|
|
undef $self->{'stderr'};
|
|
undef $self->{'pid'};
|
|
}
|
|
|
|
sub check($)
|
|
{
|
|
my($self) = @_;
|
|
|
|
if (!defined $self->{'pid'}) {
|
|
return "Product not running.";
|
|
}
|
|
|
|
my $kid = waitpid($self->{'pid'}, WNOHANG);
|
|
|
|
if ($kid) {
|
|
my $retval = $?;
|
|
my $signal = $retval & 127;
|
|
$retval = $retval >> 8;
|
|
|
|
$self->readout();
|
|
$self->discard();
|
|
|
|
return "Product has crashed, signal $signal retcode $retval.";
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub stop($)
|
|
{
|
|
my($self) = @_;
|
|
|
|
my $ret = $self->check();
|
|
return $ret if ($ret ne 1);
|
|
|
|
my $pid = $self->{'pid'};
|
|
|
|
my $hits = kill("TERM", $pid);
|
|
if ($hits < 1) {
|
|
return "Product is not running.";
|
|
$self->discard();
|
|
return undef;
|
|
}
|
|
|
|
my $sleeptime = 0.2;
|
|
my $maxwait = 6;
|
|
my $slept = 0;
|
|
my $rekilled = 0;
|
|
my $kid;
|
|
while (!($kid = waitpid($pid, WNOHANG))) {
|
|
select(undef, undef, undef, $sleeptime);
|
|
$slept += $sleeptime;
|
|
if ($slept >= $maxwait) {
|
|
if ($rekilled) {
|
|
return "Product refuses to die!";
|
|
} else {
|
|
warn "Sending SIGKILL...\n";
|
|
$slept = 0;
|
|
$rekilled = 1;
|
|
kill("KILL", $pid);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($kid) {
|
|
my $retval = $?;
|
|
my $signal = $retval & 127;
|
|
$retval = $retval >> 8;
|
|
|
|
$self->readout();
|
|
$self->discard();
|
|
if ($retval ne 0 || $signal ne 0) {
|
|
if (defined $self->{'prod'}->{'exitcode'} && $self->{'prod'}->{'exitcode'} eq $retval) {
|
|
# fine
|
|
} elsif (defined $self->{'prod'}->{'dieswith'} && $self->{'prod'}->{'dieswith'} eq $signal) {
|
|
# fine
|
|
} else {
|
|
return "Product has been terminated, signal $signal retcode $retval.";
|
|
}
|
|
}
|
|
}
|
|
|
|
$self->discard();
|
|
return 1;
|
|
}
|
|
|
|
1;
|