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 )