Algorithm-EventsPerSecond
view release on metacpan or search on metacpan
t/sukkal-lifecycle.t view on Meta::CPAN
my $d = spawn_daemon( socket_mode => '0700' );
is( ( stat $d->{path} )[2] & oct('07777'), oct('0700'), 'socket_mode applied to the socket file' );
stop_daemon($d);
}
#
# max_clients: connections over the cap are closed immediately, and a
# freed slot becomes usable again
#
{
my $d = spawn_daemon( max_clients => 2 );
my $a = connect_daemon($d);
is( req( $a, 'PING' ), 'OK PONG', 'first client served' );
my $b = connect_daemon($d);
is( req( $b, 'PING' ), 'OK PONG', 'second client served' );
like( req( $a, 'STATS' ), qr/\bclients=2\b/, 'STATS counts both clients' );
my $over = connect_daemon($d);
is( read_line($over), undef, 'client over max_clients is closed immediately' );
is( req( $a, 'PING' ), 'OK PONG', 'existing clients unaffected by the rejected one' );
close $b;
my $served;
for ( 1 .. 100 ) { # the daemon frees the slot when it notices the EOF
my $again = connect_daemon($d);
my $reply = req( $again, 'PING' );
close $again;
if ( defined $reply && $reply eq 'OK PONG' ) { $served = 1; last }
sleep 0.1;
}
ok( $served, 'slot freed after a client disconnects' );
stop_daemon($d);
}
#
# two connections driven with interleaved, pipelined traffic: each
# gets its own replies, in the order it asked, on its own socket --
# no cross-talk between the multiplexed clients
#
{
my $d = spawn_daemon;
my $a = connect_daemon($d);
my $b = connect_daemon($d);
# intermix the writes on the wire: A marks alpha, B marks beta,
# back and forth. MARK is fire-and-forget, so nothing to read yet.
for ( 1 .. 20 ) {
print $a "MARK alpha\n";
print $b "MARK beta 2\n";
}
# each connection pipelines a query then a PING; replies must come
# back on the asking socket, in the order that connection asked. A
# connection's own marks always precede its own query (same buffer,
# processed in order), so each sees its full count. Cross-connection
# ordering within a select pass is deliberately not relied on.
print $a "COUNT alpha\n";
print $a "PING\n";
print $b "COUNT beta\n";
print $b "PING\n";
is( read_line($a), 'OK 20', 'A: COUNT reflects its own 20 alpha marks' );
is( read_line($a), 'OK PONG', 'A: PING answered next, in order, on A' );
is( read_line($b), 'OK 40', 'B: COUNT reflects its own 40 beta marks' );
is( read_line($b), 'OK PONG', 'B: PING answered next, in order, on B' );
# a tighter interleave: if replies were misrouted, A's PONG could
# surface on B. Confirm each PING is answered on its own socket.
print $a "PING\n";
print $b "PING\n";
print $b "PING\n";
print $a "PING\n";
is( read_line($a), 'OK PONG', 'A: PING answered on A' );
is( read_line($a), 'OK PONG', 'A: second PING answered on A' );
is( read_line($b), 'OK PONG', 'B: PING answered on B' );
is( read_line($b), 'OK PONG', 'B: second PING answered on B' );
like( req( $a, 'STATS' ), qr/\bclients=2\b/, 'both connections live at once' );
close $a;
close $b;
stop_daemon($d);
}
#
# idle keys are evicted by the sweep, and eviction forgets the
# lifetime total, as documented
#
{
my $d = spawn_daemon( window => 1, idle_timeout => 1, sweep_interval => 1 );
my $s = connect_daemon($d);
print $s "MARK doomed 7\n";
my ($hdr) = req_multi( $s, 'KEYS' );
is( $hdr, 'OK 1', 'key tracked after mark' );
my $gone;
for ( 1 .. 100 ) { # eviction is due ~2s after the mark
($hdr) = req_multi( $s, 'KEYS' );
if ( $hdr eq 'OK 0' ) { $gone = 1; last }
sleep 0.1;
}
ok( $gone, 'idle key evicted by the sweep' );
is( req( $s, 'TOTAL doomed' ), 'OK 0', 'lifetime total is forgotten with the eviction' );
is( stop_daemon($d), 0, 'sweep daemon exits cleanly' );
}
done_testing();
( run in 0.786 second using v1.01-cache-2.11-cpan-7fcb06a456a )