IPC-Manager
view release on metacpan or search on metacpan
t/unit/peer_active_timeout.t view on Meta::CPAN
use Test2::V0;
use Time::HiRes qw/time/;
use IPC::Manager::Client;
local $SIG{ALRM} = sub { die "test timed out after 30s\n" };
alarm 30;
{
package TestPeerReady::MockClient;
use parent -norequire, 'IPC::Manager::Client';
# Instance-level toggles so tests can flip state mid-call via SIGALRM.
sub new {
my ($class, %args) = @_;
my $self = {
alive => 0,
peer_pid => $$, # use our own pid so pid_is_running returns 1
pid => $$, # satisfy pid_check in disconnect
want_peer_change_handles => 0,
%args,
};
return bless $self, $class;
}
sub peer_pid { $_[0]->{alive} ? $_[0]->{peer_pid} : 0 }
sub have_handles_for_peer_change { $_[0]->{want_peer_change_handles} }
sub handles_for_peer_change { () }
sub reset_handles_for_peer_change { }
sub disconnect { }
sub write_stats { }
sub activate_peer { $_[0]->{alive} = 1 }
}
subtest 'no timeout = one-shot behavior (backward compat)' => sub {
my $c = TestPeerReady::MockClient->new;
is($c->peer_active('foo'), 0, "inactive one-shot returns 0");
$c->activate_peer;
is($c->peer_active('foo'), 1, "active one-shot returns 1");
};
subtest 'positive timeout: returns immediately when peer is already active' => sub {
my $c = TestPeerReady::MockClient->new(alive => 1);
my $start = time;
my $got = $c->peer_active('foo', 5);
my $elapsed = time - $start;
ok($got, "returns truthy when peer is active");
ok($elapsed < 0.5, "returned quickly (${elapsed}s)");
};
subtest 'positive timeout: returns 0 after timeout when peer never becomes active' => sub {
my $c = TestPeerReady::MockClient->new; # inactive
my $start = time;
my $got = $c->peer_active('foo', 0.3);
my $elapsed = time - $start;
ok(!$got, "returned false after timeout");
ok($elapsed >= 0.25, "waited close to full timeout (${elapsed}s)");
ok($elapsed < 10, "did not wait much past timeout (${elapsed}s)");
};
subtest 'timeout 0 = block forever until peer becomes active' => sub {
my $c = TestPeerReady::MockClient->new;
# Arrange for the peer to flip to active via SIGALRM in ~0.4s.
local $SIG{ALRM} = sub { $c->activate_peer };
Time::HiRes::alarm(0.4);
my $start = time;
my $got = $c->peer_active('foo', 0);
my $elapsed = time - $start;
alarm 30; # restore outer fail-safe
ok($got, "eventually returned true once the peer became active");
ok($elapsed >= 0.3, "waited until the peer became active (${elapsed}s)");
ok($elapsed < 5, "did not hang past the activation event (${elapsed}s)");
};
subtest 'polling path: uses IO::Select when client has peer-change handles' => sub {
pipe(my ($rh, $wh)) or die "pipe: $!";
my $c = TestPeerReady::MockClient->new(
want_peer_change_handles => 1,
);
# Override to return the pipe read end.
no warnings 'redefine';
local *TestPeerReady::MockClient::handles_for_peer_change = sub { $rh };
# Make the read end ready for reading: a write wakes IO::Select up.
syswrite($wh, "x") or die "syswrite: $!";
# Peer is already active â this should return right away regardless,
# but the main point is verifying the IO::Select path does not
# deadlock or produce errors when have_handles_for_peer_change is
# true.
$c->activate_peer;
my $start = time;
my $got = $c->peer_active('foo', 2);
( run in 2.323 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )