Acme-Parataxis
view release on metacpan or search on metacpan
t/201_actor_registry.t view on Meta::CPAN
is Acme::Parataxis->actor('dup'), $a, 'the first actor still owns the name';
$a->stop;
yield while $a->is_alive;
my $b = Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { return $msg }, 16, name => 'dup' );
is Acme::Parataxis->actor('dup'), $b, 'the name is reusable once the holder is gone';
$b->stop;
};
};
subtest 'bad names are rejected; undef means unnamed' => sub {
async {
for my $bad ( '', {}, [] ) {
my $died = dies {
Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { }, 4, name => $bad );
};
ok $died, 'a non-string name croaks';
like "$died", qr/non-empty string/, 'with the reason';
}
my $u = Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { return $msg }, 4, name => undef );
is $u->name, undef, 'name => undef leaves the actor unnamed';
$u->stop;
yield while $u->is_alive;
};
};
subtest 'swap: the in-flight message keeps the old code, later ones get the new' => sub {
async {
my $actor = Acme::Parataxis::Actor->spawn(
sub ( $self, $msg ) {
if ( $msg eq 'slow' ) { Acme::Parataxis::await_sleep(300); return 'old-slow' }
return 'old';
},
16,
);
my $inflight = $actor->ask('slow');
yield; # let the actor pick 'slow' up and park inside the OLD handler
$actor->swap( sub ( $self, $msg ) { return 'new' } );
is $actor->ask('x')->await, 'new', 'a message dispatched after swap() runs the new code';
is $inflight->await, 'old-slow', 'the message that was in flight finished with the old code';
$actor->stop;
};
};
subtest 'double swap: the last handler wins' => sub {
async {
my $actor = Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { return 'one' }, 4 );
$actor->swap( sub ( $self, $msg ) { return 'two' } );
$actor->swap( sub ( $self, $msg ) { return 'three' } );
is $actor->ask('x')->await, 'three', 'the second swap replaced the first';
$actor->stop;
};
};
subtest 'swap validates its argument and refuses a dead actor' => sub {
async {
my $actor = Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { return 1 }, 4 );
like dies { $actor->swap(42) }, qr[CODE], 'swap() rejects a non-CODE';
$actor->stop;
yield while $actor->is_alive;
like dies {
$actor->swap( sub {1} )
}, qr[no longer running], 'swap() on a dead actor croaks';
};
};
subtest 'a supervisor-style respawn inherits the registered name' => sub {
async {
my $actor = Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { die "boom\n" }, 4, supervised => 1, name => 'svc' );
my $reply = $actor->ask('anything');
eval { $reply->await; 1 };
while ( $actor->is_alive ) {yield}
is Acme::Parataxis->actor('svc'), undef, 'the crashed actor released the name';
my $fresh = $actor->respawn;
is $fresh->name, 'svc', 'the restarted actor keeps the name';
is Acme::Parataxis->actor('svc'), $fresh, 'and answers the lookup, so the registry key survives restarts';
$fresh->stop;
yield while $fresh->is_alive;
is Acme::Parataxis->actor('svc'), undef, 'released again at stop';
};
};
subtest 'the registration is a strong handle: a named actor outlives dropped callers' => sub {
async {
my $actor = Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { return 'alive' }, 4, name => 'keep' );
weaken( my $w = $actor );
undef $actor; # every caller drops the handle...
ok defined $w, 'the registry keeps the actor alive'; # ...but the name still holds it
my $h = Acme::Parataxis->actor('keep');
ok defined $h && $h->is_alive, 'still reachable and running';
is $h->ask('x')->await, 'alive', 'and still answering';
$h->stop;
yield while $h->is_alive;
is Acme::Parataxis->actor('keep'), undef, 'the name is released at stop';
$h = undef;
yield;
is $w, undef, 'the actor is collected once the name is gone';
};
};
subtest 'no leaks: the registry is empty and the actor fiber is reaped' => sub {
is keys %{$Acme::Parataxis::ACTOR_REGISTRY}, 0, 'no registered names remain at the top level';
my $base = Acme::Parataxis::get_live_fiber_count();
async {
my $a = Acme::Parataxis::Actor->spawn( sub ( $self, $msg ) { return 1 }, 4, name => 'z' );
$a->stop;
yield while $a->is_alive;
};
is Acme::Parataxis::get_live_fiber_count(), $base, 'the actor fiber was reaped';
is keys %{$Acme::Parataxis::ACTOR_REGISTRY}, 0, 'its name is gone too';
};
#
done_testing;
( run in 1.622 second using v1.01-cache-2.11-cpan-b554fb43c41 )