Hyperman

 view release on metacpan or  search on metacpan

t/71-api-in-request.t  view on Meta::CPAN

        };
    }
    if ($p eq '/big') { return [ 200, [], [ 'b' x (8 * 1024 * 1024) ] ] }
    if ($p eq '/bus') {
        my $big = Hyperman->publish('t71', 'x' x 100000);
        my $ok = Hyperman->publish('t71', 'small');
        return $out->("big=$big", "ok=$ok");
    }
    $out->('default');
};

my $hook_log = "$dir/hook.log";
open my $bigfh, '>', "$dir/big.bin" or die; print $bigfh 'b' x (8 * 1024 * 1024); close $bigfh;
my $pid = fork // die "fork: $!";
if (!$pid) {
    quiet_child(stderr => "$dir/stderr");
    open my $alog, '>>', "$dir/access.log" or die;
    open my $elog, '>>', "$dir/error.log" or die;
    Hyperman->on_worker_start(sub { open my $fh, '>>', $hook_log or die; print $fh "started $$\n"; close $fh; die "hook boom\n" });
    Hyperman->run(app => $app, host => '127.0.0.1', port => [ $pa, $pb ], workers => 1, max_pipeline => 2,
        access_log => $alog, error_log => $elog, compress => 1, compress_level => 5,
        distinct_clients => 1, bus_slot_size => 1024);
    exit 0;
}

sub connect_to {
    my $port = shift;
    for (1 .. 60) {
        my $s = IO::Socket::INET->new(PeerAddr => "127.0.0.1:$port");
        return $s if $s;
        Time::HiRes::sleep(0.1);
    }
    return;
}
sub get {
    my ($port, $path, $pause) = @_;
    my $s = connect_to($port) or return '';
    $s->syswrite("GET $path HTTP/1.1\r\nHost: a\r\nConnection: close\r\n\r\n");
    Time::HiRes::sleep($pause) if $pause;
    my $buf = '';
    eval { local $SIG{ALRM} = sub { die "timeout\n" }; alarm 15; while (my $n = $s->sysread(my $c, 1 << 20)) { $buf .= $c } alarm 0 };
    return $buf;
}
sub body { my $r = shift; (split /\r\n\r\n/, $r, 2)[1] // '' }

ok(connect_to($pa), 'the first listener is up');
like(get($pb, '/'), qr/default\z/, 'and the second, from the port list');
like(body(get($pa, '/io_ready')), qr/got=ping/, 'io_ready on a socket of the handler\'s own resolves');
like(body(get($pa, '/io_ready_closed')), qr/not an open filehandle/, 'io_ready on a closed handle is refused');
like(body(get($pa, '/pool')), qr/workers=\d+;rows=\d+;leader=Shared::Arena::Lease;dc=2/, 'the pool views answer inside a worker with a scoreboard');
like(body(get($pa, '/detach_bad')), qr/give it the PSGI env hashref.*no psgix\.hyperman\.conn.*malformed psgix\.hyperman\.conn/s, 'detach refuses a string, an env without a ticket, and a malformed one');
like(body(get($pa, '/detach_twice')), qr/already detached.*connection is gone/s, 'a second detach and a stale ticket are refused');
like(get($pa, '/detach_draining', 1), qr/response is still draining/, 'detach while a response drains is refused: the client reads nothing while the handler runs');
like(body(get($pa, '/stream_bad')), qr/give it the PSGI env hashref.*no usable psgix\.hyperman\.stream.*headers must be an array reference/s, 'stream refuses a string, an env without a ticket, and headers that are not a list');
my $aborted = get($pa, '/stream_abort');
like($aborted, qr/partial/, 'a stream abort leaves what was written');
unlike($aborted, qr/aborted=/, 'and the response that follows goes nowhere');
like(get($pa, '/stream_drop'), qr/dropped\z/, 'a stream handle dropped without close still ends the body');
like(body(get($pa, '/bus')), qr/big=-1;ok=[01]/, 'the bus refuses a message past the slot size');
Time::HiRes::sleep(0.3);
like(do { local (@ARGV, $/) = ("$dir/access.log"); <> } // '', qr/GET \/io_ready/, 'the access log glob received the lines');
like(do { local (@ARGV, $/) = ("$dir/stderr"); <> } // '', qr/on_worker_start callback died: hook boom/, 'a worker hook that dies is reported');
ok(-s $hook_log, 'after it ran');

kill 'TERM', $pid;
server_reap($pid);
done_testing;



( run in 2.124 seconds using v1.01-cache-2.11-cpan-145b269f2f3 )