Algorithm-Classifier-IsolationForest
view release on metacpan or search on metacpan
t/91-streamd.t view on Meta::CPAN
#!perl
# 91-streamd.t
#
# Integration test for `iforest streamd`: starts the daemon in the
# foreground in a forked child on a temp Unix socket and drives it over
# the JSON-lines protocol. Covers startup artefacts (socket, pid file),
# the request kinds (row / rows / cmd) and modes, client-tag echo on
# success and error, per-message error isolation, multiple concurrent
# connections, command and interval saves with the latest.json symlink,
# clean SIGTERM shutdown, resume-from-latest, and (when
# Algorithm::ToNumberMunger is installed) raw munged values that CSV
# framing could never carry.
#
# Skipped on Windows (Unix sockets + fork) and without JSON::MaybeXS.
use strict;
use warnings;
use Test::More;
use File::Temp qw(tempdir);
use File::Spec;
use IO::Select ();
use IO::Socket::UNIX ();
my $bin = File::Spec->rel2abs('bin/iforest');
plan skip_all => 'bin/iforest not found' unless -x $bin;
plan skip_all => 'streamd needs Unix sockets and fork()' if $^O eq 'MSWin32';
plan skip_all => 'JSON::MaybeXS is not installed'
unless eval { require JSON::MaybeXS; 1 };
my $JSON = JSON::MaybeXS->new( utf8 => 1 );
my $tmp = tempdir( CLEANUP => 1 );
my $sock = "$tmp/s.sock";
my $pidf = "$tmp/s.pid";
my $mdir = "$tmp/models";
my $logf = "$tmp/streamd.log";
my $latest = "$mdir/latest.json";
# sun_path caps out around 104 bytes; a deep TMPDIR would make the whole
# run fail for reasons that have nothing to do with the daemon.
plan skip_all => 'temp socket path too long for a Unix socket'
if length($sock) > 100;
my %BUF; # per-connection read buffer, for line framing
my @ALL_PIDS; # every daemon spawned, for the END sweep
# Fork+exec a daemon with the given argv and wait for its socket.
sub spawn_daemon {
my ( $wait_sock, @argv ) = @_;
my $pid = fork();
die "fork failed: $!" unless defined $pid;
if ( !$pid ) {
open( STDOUT, '>>', $logf ) or die $!;
open( STDERR, '>>', $logf ) or die $!;
exec( $^X, '-Ilib', $bin, 'streamd', '-f', @argv ) or die "exec failed: $!";
}
push @ALL_PIDS, $pid;
for ( 1 .. 100 ) {
last if -S $wait_sock;
select( undef, undef, undef, 0.1 ); ## no critic (ProhibitSleepViaSelect)
}
return $pid;
} ## end sub spawn_daemon
sub start_daemon {
my (@extra) = @_;
return spawn_daemon(
$sock,
'--socket' => $sock,
'--pid' => $pidf,
'--model-dir' => $mdir,
'--log' => $logf,
@extra
);
} ## end sub start_daemon
sub stop_daemon {
my ($pid) = @_;
kill( 'TERM', $pid );
waitpid( $pid, 0 );
return $? >> 8;
}
sub connect_client {
my ($path) = @_;
$path //= $sock;
my $s = IO::Socket::UNIX->new( Peer => $path )
or die "connect to $path failed: $!";
$s->autoflush(1);
$BUF{ fileno($s) } = '';
( run in 2.185 seconds using v1.01-cache-2.11-cpan-600a1bdf6e4 )