File Coverage

inc/Test/TCP.pm
Criterion Covered Total %
statement 30 82 36.5
branch 0 28 0.0
condition 0 11 0.0
subroutine 10 16 62.5
pod 2 3 66.6
total 42 140 30.0


line stmt bran cond sub pod time code
1             #line 1
2 7     7   6758 package Test::TCP;
  7         13  
  7         395  
3 7     7   34 use strict;
  7         12  
  7         164  
4 7     7   178 use warnings;
  7         40  
  7         391  
5             use 5.00800;
6 7     7   46 our $VERSION = '0.16';
  7         12  
  7         53  
7 7     7   7748 use base qw/Exporter/;
  7         212198  
  7         78  
8 7     7   11856 use IO::Socket::INET;
  7         7825  
  7         94  
9 7     7   69 use Test::SharedFork;
  7         17  
  7         116  
10 7     7   39 use Test::More ();
  7         13  
  7         209  
11 7     7   6605 use Config;
  7         56277  
  7         49  
12 7     7   29544 use POSIX;
  7         13835  
  7         5852  
13             use Time::HiRes ();
14              
15             # process does not die when received SIGTERM, on win32.
16             my $TERMSIG = $^O eq 'MSWin32' ? 'KILL' : 'TERM';
17              
18             our @EXPORT = qw/ empty_port test_tcp wait_port /;
19              
20 0   0 0 0   sub empty_port {
21 0 0 0       my $port = shift || 10000;
22             $port = 19000 unless $port =~ /^[0-9]+$/ && $port < 19000;
23 0            
24 0 0         while ( $port++ < 20000 ) {
25             my $sock = IO::Socket::INET->new(
26             Listen => 5,
27             LocalAddr => '127.0.0.1',
28             LocalPort => $port,
29             Proto => 'tcp',
30             (($^O eq 'MSWin32') ? () : (ReuseAddr => 1)),
31 0 0         );
32             return $port if $sock;
33 0           }
34             die "empty port not found";
35             }
36              
37 0     0 1   sub test_tcp {
38 0           my %args = @_;
39 0 0         for my $k (qw/client server/) {
40             die "missing madatory parameter $k" unless exists $args{$k};
41 0   0       }
42             my $port = $args{port} || empty_port();
43 0 0          
    0          
44             if ( my $pid = Test::SharedFork->fork() ) {
45 0           # parent.
46             wait_port($port);
47 0            
48             my $sig;
49             my $err;
50 0     0     {
  0            
  0            
  0            
51 0     0     local $SIG{INT} = sub { $sig = "INT"; die "SIGINT received\n" };
  0            
  0            
52 0           local $SIG{PIPE} = sub { $sig = "PIPE"; die "SIGPIPE received\n" };
53 0           eval {
54             $args{client}->($port, $pid);
55 0           };
56             $err = $@;
57              
58 0           # cleanup
59 0           kill $TERMSIG => $pid;
60 0           while (1) {
61 0 0         my $kid = waitpid( $pid, 0 );
62 0 0         if ($^O ne 'MSWin32') { # i'm not in hell
63 0           if (WIFSIGNALED($?)) {
64 0 0         my $signame = (split(' ', $Config{sig_name}))[WTERMSIG($?)];
65 0           if ($signame =~ /^(ABRT|PIPE)$/) {
66             Test::More::diag("your server received SIG$signame");
67             }
68             }
69 0 0 0       }
70 0           if ($kid == 0 || $kid == -1) {
71             last;
72             }
73             }
74             }
75 0 0          
76 0           if ($sig) {
77             kill $sig, $$; # rethrow signal after cleanup
78 0 0         }
79 0           if ($err) {
80             die $err; # rethrow exception after cleanup.
81             }
82             }
83             elsif ( $pid == 0 ) {
84 0           # child
85 0           $args{server}->($port);
86             exit;
87             }
88 0           else {
89             die "fork failed: $!";
90             }
91             }
92              
93 0     0     sub _check_port {
94             my ($port) = @_;
95 0            
96             my $remote = IO::Socket::INET->new(
97             Proto => 'tcp',
98             PeerAddr => '127.0.0.1',
99             PeerPort => $port,
100 0 0         );
101 0           if ($remote) {
102 0           close $remote;
103             return 1;
104             }
105 0           else {
106             return 0;
107             }
108             }
109              
110 0     0 1   sub wait_port {
111             my $port = shift;
112 0            
113 0           my $retry = 100;
114 0 0         while ( $retry-- ) {
115 0           return if _check_port($port);
116             Time::HiRes::sleep(0.1);
117 0           }
118             die "cannot open port: $port";
119             }
120              
121             1;
122             __END__
123              
124             =encoding utf8
125              
126             #line 241