File Coverage

inc/Test/TCP.pm
Criterion Covered Total %
statement 67 79 84.8
branch 16 26 61.5
condition 5 11 45.4
subroutine 13 15 86.6
pod 2 3 66.6
total 103 134 76.8


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