1#!/usr/bin/perl 2 3use strict; 4use warnings; 5 6use Test::More; 7 8use IO::Async::Test; 9use IO::Async::Loop; 10 11use Net::Async::HTTP; 12 13my $CRLF = "\x0d\x0a"; # because \r\n isn't portable 14 15my $loop = IO::Async::Loop->new(); 16testing_loop( $loop ); 17 18my $http = Net::Async::HTTP->new( 19 user_agent => "", # Don't put one in request headers 20); 21 22$loop->add( $http ); 23 24my $peersock; 25no warnings 'redefine'; 26local *IO::Async::Handle::connect = sub { 27 my $self = shift; 28 my %args = @_; 29 $args{host} eq "localhost" or die "Cannot fake connect - expected host 'localhost'"; 30 $args{service} eq "5000" or die "Cannot fake connect - expected service '5000'"; 31 32 ( my $selfsock, $peersock ) = IO::Async::OS->socketpair() or die "Cannot create socket pair - $!"; 33 $self->set_handle( $selfsock ); 34 35 return Future->done( $self ); 36}; 37 38# Without on_error 39{ 40 my $f1 = $http->GET( "http://localhost:5000/1" ) 41 ->on_done( sub { die "Oopsie" } ); 42 43 my $f2 = $http->GET( "http://localhost:5000/2" ); 44 45 wait_for { defined $peersock }; 46 47 my $request_stream = ""; 48 49 wait_for_stream { $request_stream =~ m/$CRLF$CRLF/ } $peersock => $request_stream; 50 pass( "First request is made" ); 51 52 $request_stream =~ s/^.*$CRLF$CRLF//s; 53 54 $peersock->syswrite( "HTTP/1.1 200 OK$CRLF" . 55 "Content-Length: 0$CRLF" . 56 $CRLF ); 57 58 my $e = eval { $loop->loop_once(0) for 1 .. 5; 1 } ? undef : $@; 59 like( $e, qr/^Oopsie at \Q$0\E line \d+/, 60 'Oopsie exception caught at loop toplevel' ); 61 62 wait_for_stream { $request_stream =~ m/$CRLF$CRLF/ } $peersock => $request_stream; 63 pass( "Second request is made after first one dies at ->done" ); 64 65 $request_stream =~ s/^.*$CRLF$CRLF//s; 66 67 $peersock->syswrite( "HTTP/1.1 200 OK$CRLF" . 68 "Content-Length: 0$CRLF" . 69 $CRLF ); 70 71 wait_for_future( $f2 ); 72 ok( !$f2->failure, '$f2 completes successfully' ); 73} 74 75# With on_error 76{ 77 my $error; 78 $http->configure( 79 on_error => sub { ( undef, $error ) = @_; }, 80 ); 81 82 my $f1 = $http->GET( "http://localhost:5000/1" ) 83 ->on_done( sub { die "Oopsie" } ); 84 85 my $f2 = $http->GET( "http://localhost:5000/2" ); 86 87 wait_for { defined $peersock }; 88 89 my $request_stream = ""; 90 91 wait_for_stream { $request_stream =~ m/$CRLF$CRLF/ } $peersock => $request_stream; 92 pass( "First request is made" ); 93 94 $request_stream =~ s/^.*$CRLF$CRLF//s; 95 96 $peersock->syswrite( "HTTP/1.1 200 OK$CRLF" . 97 "Content-Length: 0$CRLF" . 98 $CRLF ); 99 100 my $e = eval { $loop->loop_once(0) for 1 .. 5; 1 } ? undef : $@; 101 ok( !defined $e, 'Loop toplevel does not catch exception' ) or 102 diag( "Caught exception was: $e" ); 103 104 like( $error, qr/^Oopsie at \Q$0\E line \d+/, 105 'Oopsie exception caught by on_error handler' ); 106 107 wait_for_stream { $request_stream =~ m/$CRLF$CRLF/ } $peersock => $request_stream; 108 pass( "Second request is made after first one dies at ->done" ); 109 110 $request_stream =~ s/^.*$CRLF$CRLF//s; 111 112 $peersock->syswrite( "HTTP/1.1 200 OK$CRLF" . 113 "Content-Length: 0$CRLF" . 114 $CRLF ); 115 116 wait_for_future( $f2 ); 117 ok( !$f2->failure, '$f2 completes successfully' ); 118} 119 120done_testing; 121