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 1     1   1644 package Test::TCP;
  1         2  
  1         34  
3 1     1   5 use strict;
  1         2  
  1         25  
4 1     1   24 use warnings;
  1         6  
  1         59  
5             use 5.00800;
6 1     1   6 our $VERSION = '0.16';
  1         2  
  1         8  
7 1     1   1081 use base qw/Exporter/;
  1         29610  
  1         8  
8 1     1   2401 use IO::Socket::INET;
  1         1069  
  1         14  
9 1     1   10 use Test::SharedFork;
  1         2  
  1         15  
10 1     1   5 use Test::More ();
  1         2  
  1         28  
11 1     1   969 use Config;
  1         6340  
  1         6  
12 1     1   4823 use POSIX;
  1         2234  
  1         879  
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