Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/IO/Async/LoopTests.pm view on Meta::CPAN
Tests the Loop's support for idle handlers
=cut
use constant count_tests_idle => 11;
sub run_tests_idle
{
my $called = 0;
my $id = $loop->watch_idle( when => 'later', code => sub { $called = 1 } );
ok( defined $id, 'idle watcher id is defined' );
is( $called, 0, 'deferred sub not yet invoked' );
time_between { $loop->loop_once( 3 * AUT ) } undef, 1.0, 'loop_once(3) with deferred sub';
is( $called, 1, 'deferred sub called after loop_once' );
$loop->watch_idle( when => 'later', code => sub {
$loop->watch_idle( when => 'later', code => sub { $called = 2 } )
} );
$loop->loop_once( 1 );
is( $called, 1, 'inner deferral not yet invoked' );
$loop->loop_once( 1 );
is( $called, 2, 'inner deferral now invoked' );
$called = 2; # set it anyway in case previous test fails
$id = $loop->watch_idle( when => 'later', code => sub { $called = 20 } );
$loop->unwatch_idle( $id );
time_between { $loop->loop_once( 1 * AUT ) } 0.5, 1.5, 'loop_once(1) with unwatched deferral';
is( $called, 2, 'unwatched deferral not called' );
$id = $loop->watch_idle( when => 'later', code => sub { $called = 3 } );
my $timer_id = $loop->watch_time( after => 5, code => sub {} );
$loop->loop_once( 1 );
is( $called, 3, '$loop->later still invoked with enqueued timer' );
$loop->unwatch_time( $timer_id );
$loop->later( sub { $called = 4 } );
$loop->loop_once( 1 );
is( $called, 4, '$loop->later shortcut works' );
}
=head2 child
Tests the Loop's support for watching child processes by PID
=cut
sub run_in_child(&)
{
my $kid = fork;
defined $kid or die "Cannot fork() - $!";
return $kid if $kid;
shift->();
die "Fell out of run_in_child!\n";
}
use constant count_tests_child => 7;
sub run_tests_child
{
my $kid = run_in_child {
exit( 3 );
};
my $exitcode;
$loop->watch_child( $kid => sub { ( undef, $exitcode ) = @_; } );
is_oneref( $loop, '$loop has refcount 1 after watch_child' );
ok( !defined $exitcode, '$exitcode not defined before ->loop_once' );
undef $exitcode;
wait_for { defined $exitcode };
ok( ($exitcode & 0x7f) == 0, 'WIFEXITED($exitcode) after child exit' );
is( ($exitcode >> 8), 3, 'WEXITSTATUS($exitcode) after child exit' );
SKIP: {
skip "This OS does not have signals", 1 unless IO::Async::OS->HAVE_SIGNALS;
# We require that SIGTERM perform its default action; i.e. terminate the
# process. Ensure this definitely happens, in case the test harness has it
# ignored or handled elsewhere.
local $SIG{TERM} = "DEFAULT";
$kid = run_in_child {
sleep( 10 );
# Just in case the parent died already and didn't kill us
exit( 0 );
};
$loop->watch_child( $kid => sub { ( undef, $exitcode ) = @_; } );
kill SIGTERM, $kid;
undef $exitcode;
wait_for { defined $exitcode };
is( ($exitcode & 0x7f), SIGTERM, 'WTERMSIG($exitcode) after SIGTERM' );
}
my %kids;
$loop->watch_child( 0 => sub { my ( $kid ) = @_; delete $kids{$kid} } );
%kids = map { run_in_child { exit 0 } => 1 } 1 .. 3;
is( scalar keys %kids, 3, 'Waiting for 3 child processes' );
wait_for { !keys %kids };
ok( !keys %kids, 'All child processes reclaimed' );
}
=head2 control
Tests that the C<run>, C<stop>, C<loop_once> and C<loop_forever> methods
behave correctly
=cut
use constant count_tests_control => 8;
sub run_tests_control
{
time_between { $loop->loop_once( 0 ) } 0, 0.1, 'loop_once(0) when idle';
time_between { $loop->loop_once( 2 * AUT ) } 1.5, 2.5, 'loop_once(2) when idle';
$loop->watch_time( after => 0.1, code => sub { $loop->stop( result => "here" ) } );
local $SIG{ALRM} = sub { die "Test timed out before ->stop" };
alarm( 1 );
my @result = $loop->run;
alarm( 0 );
is_deeply( \@result, [ result => "here" ], '->stop arguments returned by ->run' );
$loop->watch_time( after => 0.1, code => sub { $loop->stop( result => "here" ) } );
my $result = $loop->run;
is( $result, "result", 'First ->stop argument returned by ->run in scalar context' );
$loop->watch_time( after => 0.1, code => sub {
$loop->watch_time( after => 0.1, code => sub { $loop->stop( "inner" ) } );
my @result = $loop->run;
$loop->stop( @result, "outer" );
} );
@result = $loop->run;
is_deeply( \@result, [ "inner", "outer" ], '->run can be nested properly' );
$loop->watch_time( after => 0.1, code => sub { $loop->loop_stop } );
local $SIG{ALRM} = sub { die "Test timed out before ->loop_stop" };
alarm( 1 );
$loop->loop_forever;
alarm( 0 );
ok( 1, '$loop->loop_forever interruptable by ->loop_stop' );
}
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
( run in 0.894 second using v1.01-cache-2.11-cpan-d7f47b0818f )