Developer-Dashboard
view release on metacpan or search on metacpan
t/109-saved-ajax-process-tree.t view on Meta::CPAN
if ( !$grandchild ) {
close STDOUT;
close STDERR;
$SIG{TERM} = 'IGNORE';
open my $marker_fh, '>', $marker or exit 91;
print {$marker_fh} "$$\n";
close $marker_fh or exit 92;
sleep 30;
exit 0;
}
for ( 1 .. 100 ) {
last if -s $marker;
select undef, undef, undef, 0.02;
}
print "worker=$$ grandchild=$grandchild\n";
$SIG{TERM} = sub { exit 0 };
sleep 30;
SAVED_AJAX
close $saved_fh or die "Unable to close $saved_path: $!";
chmod 0700, $saved_path or die "Unable to chmod $saved_path: $!";
my ( $worker_pid, $grandchild_pid, $stream_result );
my $grandchild_was_live = 0;
my $run_error = '';
{
local $SIG{ALRM} = sub { die "DD-396 saved-Ajax process-tree test timed out\n" };
alarm 8;
eval {
$stream_result = $runtime->stream_saved_ajax_file(
path => $saved_path,
page => 'dd396-process-tree',
type => 'text',
params => {
file => 'dd396-process-tree.pl',
marker => $marker,
page => 'dd396-process-tree',
type => 'text',
},
stdout_writer => sub {
my ($chunk) = @_;
if ( defined $chunk && $chunk =~ /worker=(\d+)\s+grandchild=(\d+)/ ) {
( $worker_pid, $grandchild_pid ) = ( $1 + 0, $2 + 0 );
$grandchild_was_live = _process_is_live($grandchild_pid);
}
return 0;
},
stderr_writer => sub { return 0 },
);
1;
} or do {
$run_error = $@ || 'unknown stream error';
};
alarm 0;
}
$grandchild_pid ||= _read_pid_marker($marker);
# Feature: Saved-Ajax cancellation owns the complete POSIX process tree.
# Scenario: Browser disconnects after a saved-Ajax worker forks a descendant.
# Given the worker and TERM-ignoring grandchild are both running,
ok( defined $worker_pid && $worker_pid > 0, 'BDD Given: saved-Ajax worker reports its pid before disconnect' );
ok( $grandchild_was_live, 'BDD Given: saved-Ajax grandchild is alive before disconnect cleanup' );
# When the response writer reports the browser disconnect,
is( $run_error, '', 'BDD When: disconnect cleanup returns without an internal runtime error' );
ok( $stream_result && $stream_result->{disconnected}, 'ATDD: saved-Ajax result records the writer disconnect' );
# Then no runnable descendant remains after the bounded cleanup.
ok(
defined $grandchild_pid && _wait_until( sub { !_process_is_live($grandchild_pid) }, 2 ),
'ATDD Then: disconnect cleanup terminates the saved-Ajax grandchild process',
);
if ( defined $grandchild_pid && _process_is_live($grandchild_pid) ) {
diag("RED cleanup: terminating leaked saved-Ajax grandchild pid=$grandchild_pid marker=$marker");
_stop_process($grandchild_pid)
or diag("RED cleanup FAILED: saved-Ajax grandchild pid=$grandchild_pid is still live");
}
unlink $marker if -e $marker;
}
done_testing;
__END__
=head1 NAME
109-saved-ajax-process-tree.t - saved-Ajax disconnect process-tree acceptance test
=head1 DESCRIPTION
This test proves that disconnecting a streamed saved-Ajax response terminates
both the directly launched worker and a real TERM-ignoring grandchild on POSIX.
It uses a unique temporary marker, bounded waits, and an explicit cleanup path
so a failing regression test does not leave a runnable descendant behind.
=for comment FULL-POD-DOC START
=head1 PURPOSE
Protect the saved-Ajax lifecycle contract at the process boundary rather than
mocking signal calls. The scenario reproduces the browser-disconnect path and
observes the descendant process directly.
=head1 WHY IT EXISTS
Terminating only the worker pid can orphan commands forked by a saved-Ajax
handler. A real process-tree fixture catches that leak and prevents direct-pid
cleanup from being mistaken for complete cancellation.
=head1 WHEN TO USE
Run this test whenever saved-Ajax launch, stream cancellation, signal handling,
or process ownership changes.
=head1 HOW TO USE
Run C<prove -lv t/109-saved-ajax-process-tree.t> for the focused TDD, BDD, and
ATDD loop. Then include it in the repository-wide tests and platform gates.
=head1 WHAT USES IT
Developers, the Perl test harness, and the saved-Ajax lifecycle delivery gates
use this executable scenario.
( run in 0.632 second using v1.01-cache-2.11-cpan-14f38c9f855 )