use strict;
use warnings;
use IO::Async::PSGI;
use IO::Async::Loop;
use IO::Async::Test;
use HTTP::Request;
use HTTP::Message::PSGI;
use HTTP::Exception;
use Test2::Bundle::Extended;
use Data::Printer;
my $loop = IO::Async::Loop->new;
testing_loop $loop;
my $app_f = sub {
my $f = $_[0]->{'io.async.loop'}
->delay_future(after=>0.2);
if ($_[0]->{PATH_INFO} =~ /fail/) {
return $f->then_fail("Expected failure\n");
}
if ($_[0]->{PATH_INFO} =~ /exc/) {
return $f->then_fail(
HTTP::Exception::401->throw(
status_message => 'Expected failure',
),
);
}
return $f->then_done([200,[],['coderef']]);
};
my $psgi = IO::Async::PSGI->new({
app => $app_f,
});
my $app = $psgi->psgi_app;
my $success = [200,[],['coderef']];
my $fail_500 = [ 500, array { etc; }, [ "Expected failure\n" ] ];
my $fail_401 = [ 401, array { etc; }, [ 'Expected failure' ] ];
my %cases = (
success => $success,
'/success' => $success,
fail => $fail_500,
'/fail' => $fail_500,
exception => $fail_401,
'/exception' => $fail_401,
);
sub run_test {
my ($use_loop) = @_;
for my $c (sort keys %cases) {
subtest $c => sub {
my $req = HTTP::Request->new(
GET => "http://localhost/$c",
)->to_psgi;
$req->{'io.async.loop'}=$loop
if $use_loop;
my $raw_res = $app->($req);
my $res;
ref_ok(
$raw_res,
'CODE',
'got a delayed response',
);
$raw_res->(sub{$res=shift});
wait_for { $res } if $use_loop;
is(
$res,
$cases{$c},
'correct response',
np $res,
);
}
}
}
subtest 'with loop' => sub { run_test(1) };
subtest 'without loop' => sub { run_test(0) };
package My::PSGI {
use Moo;
extends 'IO::Async::PSGI';
sub on_app_failure {
my ($self,$env,$exc,@details) = @_;
if ($exc =~ /^Expected/) {
return [ 501, [], ['something special from '.$env->{REQUEST_URI}] ];
}
return $self->next::method($env,$exc,@details);
}
};
for my $fail (qw(my/fail /my/fail /my//fail exception /exception)) {
$cases{$fail} = [501, [], ["something special from /$fail"] ];
}
delete @cases{qw(fail /fail)};
$psgi = My::PSGI->new({app=>$app_f});
$app = $psgi->psgi_app;
subtest 'custom failure handler' => sub { run_test(1) };
done_testing;