#!/usr/bin/perl -w
use strict;
use Test::More tests => 38;
use Test::Exception;
use IO::Async::ChildManager;
use POSIX qw( WIFEXITED WEXITSTATUS ENOENT );
use IO::Async::Set::IO_Poll;
# Need to look this up, so we don't hardcode the message in the test script
# This might cause locale issues
use constant ENOENT_MESSAGE => do { local $! = ENOENT; "$!" };
my $manager = IO::Async::ChildManager->new();
dies_ok( sub { $manager->spawn( command => "/bin/true", on_exit => sub {} ); },
'Spawn on unassociated ChildManager fails' );
my $set = IO::Async::Set::IO_Poll->new();
$set->enable_childmanager;
$manager = $set->get_childmanager;
my $exited_pid;
my $exitcode;
my $dollarbang;
my $dollarat;
sub on_exit
{
( $exited_pid, $exitcode, $dollarbang, $dollarat ) = @_;
}
sub wait_for_exit
{
my $ready = 0;
undef $exitcode;
my ( undef, $callerfile, $callerline ) = caller();
while( !defined $exitcode ) {
$_ = $set->loop_once( 10 ); # Give code a generous 10 seconds to exit
die "Nothing was ready after 10 second wait; called at $callerfile line $callerline\n" if $_ == 0;
$ready += $_;
}
$ready;
}
dies_ok( sub { $manager->spawn( badoption => 1 ); },
'Bad option to spawn fails' );
dies_ok( sub { $manager->spawn( code => sub { 1 }, command => "hello" ); },
'Both code and command options to spawn fails' );
dies_ok( sub { $manager->spawn( on_exit => sub { 1 } ); },
'Bad option to spawn fails' );
my $spawned_pid;
$spawned_pid = $manager->spawn(
code => sub { return 42; },
on_exit => \&on_exit,
);
my $ready;
$ready = wait_for_exit;
cmp_ok( $ready, '>=', 3, '$ready after spawn CODE' );
is( $exited_pid, $spawned_pid, '$exited_pid == $spawned_pid after spawn CODE' );
ok( WIFEXITED($exitcode), 'WIFEXITED($exitcode) after spawn CODE' );
is( WEXITSTATUS($exitcode), 42, 'WEXITSTATUS($exitcode) after spawn CODE' );
# dollarbang isn't interesting here
is( $dollarat, '', '$dollarat after spawn CODE' );
my $ENDEXIT = 10;
END { exit $ENDEXIT if defined $ENDEXIT; }
$spawned_pid = $manager->spawn(
code => sub { return 0; },
on_exit => \&on_exit,
);
$ready = wait_for_exit;
cmp_ok( $ready, '>=', 3, '$ready after spawn CODE with END' );
is( $exited_pid, $spawned_pid, '$exited_pid == $spawned_pid after spawn CODE with END' );
ok( WIFEXITED($exitcode), 'WIFEXITED($exitcode) after spawn CODE with END' );
# If this comes out as 10 then the END block ran and we fail.
is( WEXITSTATUS($exitcode), 0, 'WEXITSTATUS($exitcode) after spawn CODE with END' );
# dollarbang isn't interesting here
is( $dollarat, '', '$dollarat after spawn CODE with END' );
$spawned_pid = $manager->spawn(
code => sub { die "An exception here\n"; },
on_exit => \&on_exit,
);
$ready = wait_for_exit;
cmp_ok( $ready, '>=', 3, '$ready after spawn CODE with die with END' );
is( $exited_pid, $spawned_pid, '$exited_pid == $spawned_pid after spawn CODE with die with END' );
ok( WIFEXITED($exitcode), 'WIFEXITED($exitcode) after spawn CODE with die with END' );
is( WEXITSTATUS($exitcode), 255, 'WEXITSTATUS($exitcode) after spawn CODE with die with END' );
# dollarbang isn't interesting here
is( $dollarat, "An exception here\n", '$dollarat after spawn CODE with die with END' );
undef $ENDEXIT;
# We need a command that just exits immediately with 0
my $true;
foreach (qw( /bin/true /usr/bin/true )) {
$true = $_, last if -x $_;
}
# Didn't find a likely-looking candidate. We'll fake one using perl itself
$true = "$^X -e 1" if !defined $true;
$spawned_pid = $manager->spawn(
command => $true,
on_exit => \&on_exit,
);
$ready = wait_for_exit;
is( $ready, 2, '$ready after spawn '.$true );
is( $exited_pid, $spawned_pid, '$exited_pid == $spawned_pid after spawn '.$true );
ok( WIFEXITED($exitcode), 'WIFEXITED($exitcode) after spawn '.$true );
is( WEXITSTATUS($exitcode), 0, 'WEXITSTATUS($exitcode) after spawn '.$true );
is( $dollarbang+0, 0, '$dollarbang after spawn '.$true );
is( $dollarat, '', '$dollarat after spawn '.$true );
# Just be paranoid in case anyone actually has this
my $donotexist = "/bin/donotexist";
$donotexist .= "X" while -e $donotexist;
$spawned_pid = $manager->spawn(
command => $donotexist,
on_exit => \&on_exit,
);
$ready = wait_for_exit;
cmp_ok( $ready, '>=', 3, '$ready after spawn donotexist' );
is( $exited_pid, $spawned_pid, '$exited_pid == $spawned_pid after spawn donotexist' );
ok( WIFEXITED($exitcode), 'WIFEXITED($exitcode) after spawn donotexist' );
is( WEXITSTATUS($exitcode), 255, 'WEXITSTATUS($exitcode) after spawn donotexist' );
is( $dollarbang+0, ENOENT, '$dollarbang numerically after spawn donotexist' );
is( "$dollarbang", ENOENT_MESSAGE, '$dollarbang string after spawn donotexist' );
is( $dollarat, '', '$dollarat after spawn donotexist' );
$spawned_pid = $manager->spawn(
command => [ $^X, "-e", "exit 14" ],
on_exit => \&on_exit,
);
$ready = wait_for_exit;
is( $ready, 2, '$ready after spawn ARRAY' );
is( $exited_pid, $spawned_pid, '$exited_pid == $spawned_pid after spawn ARRAY' );
ok( WIFEXITED($exitcode), 'WIFEXITED($exitcode) after spawn ARRAY' );
is( WEXITSTATUS($exitcode), 14, 'WEXITSTATUS($exitcode) after spawn ARRAY' );
is( $dollarbang+0, 0, '$dollarbang after spawn ARRAY' );
is( $dollarat, '', '$dollarat after spawn ARRAY' );
syntax highlighted by Code2HTML, v. 0.9.1