MojoX-HTTP-Async
view release on metacpan or search on metacpan
t/lib/Test/Utils.pm view on Meta::CPAN
package Test::Utils;
use 5.020;
use strict;
use warnings;
use experimental qw/ signatures /;
use Exporter qw/ import /;
use Test::TCP ();
use Socket qw/ inet_aton sockaddr_in pack_sockaddr_in AF_INET SOCK_STREAM INADDR_ANY /;
use IO::Socket::SSL ();
use Net::EmptyPort qw/ empty_port /;
use FindBin qw/ $Bin /;
use constant {
# IS_LINUX => ($^O eq 'linux') ? 1 : 0,
# IS_DARWIN => ($^O eq 'darwin') 1 ? : 0,
# IS_WIN => ($^O eq 'MSWin32') ? 1 : 0,
IS_NOT_WIN => ($^O ne 'MSWin32') ? 1 : 0,
IS_NOT_WIN_AND_NOT_MACOS => ($^O ne 'MSWin32' && $^O ne 'darwin') ? 1 : 0,
};
our @EXPORT = ();
our @EXPORT_OK = qw/ get_free_port get_listen_socket start_server notify_parent IS_NOT_WIN IS_NOT_WIN_AND_NOT_MACOS /;
our %EXPORT_TAGS = ();
our $PPID;
sub notify_parent () {
if (&IS_NOT_WIN) {
kill('USR1', $PPID) if defined($PPID);
}
}
sub get_free_port ($start, $end, $host = 'localhost', $timeout = 0.1) {
my $free_port;
my $host_addr = inet_aton('localhost');
my $proto = getprotobyname('tcp');
socket(my $socket, AF_INET, SOCK_STREAM, $proto) || die "socket error: $!";
for my $port ($start .. $end) {
my $peerAddr = pack_sockaddr_in($port, $host_addr);
eval {
# NB: \n required
local $SIG{'ALRM'} = sub {die("alarmed\n");};
Time::HiRes::alarm($timeout // 0.1);
connect($socket, $peerAddr) || die "connect error: $!";
Time::HiRes::alarm(0);
};
my $error = $@;
Time::HiRes::alarm(0) if $error;
my $was_alarmed = ($@ && $@ eq "alarmed\n");
if ($!{'ECONNREFUSED'}) {
$free_port = $port;
last;
}
}
close($socket) if ($socket);
return $free_port;
}
sub start_server ($on_start_cb, $host = 'localhost', $server_port = undef, $attempts = 10, $wait_for_a_signal_secs = 5) {
my $can_go_further = 0;
my $server;
srand(time() + $$);
$PPID //= $$; # PID before forking the server
$server_port //= empty_port({'host' => $host, 'proto' => 'tcp', 'port' => (29152 + int(rand(1000)))});
# $server_port //= get_free_port(49152, 65000, $host);
if (&IS_NOT_WIN) {
$SIG{'USR1'} = sub ($sig) { $can_go_further = 1; };
}
while ($attempts-- > 0) {
eval {
$server = Test::TCP->new(
'max_wait' => 10,
'host' => 'localhost',
'listen' => 0,
'proto' => 'tcp',
'port' => $server_port,
'code' => $on_start_cb
);
};
my $error = $@;
last if ! $error && $server;
die($error) if $error && $error !~ m/(Address already in use)|(Connection refused)/;
}
die("Server isn't started") if ! $server;
# just an attempt to be sure that server is started
my $stop_waiting_ts = time() + $wait_for_a_signal_secs;
while (1) {
sleep(0.01);
last if (time() < $stop_waiting_ts);
last if $can_go_further;
}
if (&IS_NOT_WIN) {
$SIG{'USR1'} = 'DEFAULT';
}
return $server;
}
sub get_listen_socket ($host, $port, $is_ssl = 0) {
my $socket;
my $QUEUE_LENGTH = 3;
if ($is_ssl) {
$socket = IO::Socket::SSL->new(
'LocalAddr' => $host,
'LocalPort' => $port,
'Listen' => $QUEUE_LENGTH,
'SSL_cert_file' => "${Bin}/certs/server-cert.pem",
'SSL_key_file' => "${Bin}/certs/server-key.pem",
'SSL_passwd_cb' => sub { 1234 },
) or die "Can't create socket on port ${port}: $!";
} else {
my $my_addr = sockaddr_in($port, INADDR_ANY);
socket($socket, AF_INET, SOCK_STREAM, getprotobyname( 'tcp' ));
bind($socket, $my_addr ) or die( qq(Couldn't bind socket to port $port: $!\n));
listen($socket, $QUEUE_LENGTH) or die( "Couldn't listen port ${port}: $!\n" );
}
return $socket;
}
1;
__END__
( run in 1.838 second using v1.01-cache-2.11-cpan-39bf76dae61 )