File Coverage

inc/Test/TCP.pm
Criterion Covered Total %
statement 70 84 83.3
branch 15 34 44.1
condition 3 6 50.0
subroutine 19 20 95.0
pod 7 7 100.0
total 114 151 75.5


line stmt bran cond sub pod time code
1             #line 1
2 2     2   1880 package Test::TCP;
  2         4  
  2         76  
3 2     2   9 use strict;
  2         4  
  2         50  
4 2     2   54 use warnings;
  2         8  
  2         113  
5             use 5.00800;
6 2     2   10 our $VERSION = '1.21';
  2         3  
  2         211  
7 2     2   2051 use base qw/Exporter/;
  2         55477  
  2         15  
8 2     2   3233 use IO::Socket::INET;
  2         70025  
  2         35  
9 2     2   332 use Test::SharedFork 0.12;
  2         6  
  2         32  
10 2     2   10 use Test::More ();
  2         4  
  2         64  
11 2     2   1747 use Config;
  2         14487  
  2         12  
12 2     2   8108 use POSIX;
  2         3945  
  2         54  
13 2     2   13 use Time::HiRes ();
  2         3  
  2         40  
14 2     2   1776 use Carp ();
  2         3080  
  2         1642  
15             use Net::EmptyPort qw(empty_port check_port);
16              
17             our @EXPORT = qw/ empty_port test_tcp wait_port /;
18              
19             # process does not die when received SIGTERM, on win32.
20             my $TERMSIG = $^O eq 'MSWin32' ? 'KILL' : 'TERM';
21              
22 2     2 1 54493 sub test_tcp {
23 2         33 my %args = @_;
24 4 50       41 for my $k (qw/client server/) {
25             die "missing madatory parameter $k" unless exists $args{$k};
26 2   33     106 }
27             my $server = Test::TCP->new(
28             code => $args{server},
29             port => $args{port} || empty_port(),
30 0         0 );
31 0         0 $args{client}->($server->port, $server->pid);
32             undef $server; # make sure
33             }
34              
35 2     2 1 19 sub wait_port {
36             my $port = shift;
37 2 50       130  
38             Net::EmptyPort::wait_port($port, 0.1, 100)
39             or die "cannot open port: $port";
40             }
41              
42             # -------------------------------------------------------------------------
43             # OO-ish interface
44              
45 2     2 1 2289 sub new {
46 2 50       34 my $class = shift;
  0         0  
47 2 50       18 my %args = @_==1 ? %{$_[0]} : @_;
48 2         36 Carp::croak("missing mandatory parameter 'code'") unless exists $args{code};
49             my $self = bless {
50             auto_start => 1,
51             _my_pid => $$,
52             %args,
53 2 50       31 }, $class;
54 2 50       25 $self->{port} = empty_port() unless exists $self->{port};
55             $self->start()
56 0         0 if $self->{auto_start};
57             return $self;
58             }
59 0     0 1 0  
60 2     2 1 211 sub pid { $_[0]->{pid} }
61             sub port { $_[0]->{port} }
62              
63 2     2 1 8 sub start {
64 2 50       3039 my $self = shift;
    0          
65             if ( my $pid = fork() ) {
66 2         86 # parent.
67 2         106 $self->{pid} = $pid;
68 0         0 Test::TCP::wait_port($self->port);
69             return;
70             } elsif ($pid == 0) {
71 0         0 # child process
72             $self->{code}->($self->port);
73 0 0       0 # should not reach here
74 0         0 if (kill 0, $self->{_my_pid}) { # warn only parent process still exists
75             warn("[Test::TCP] Child process does not block(PID: $$, PPID: $self->{_my_pid})");
76 0         0 }
77             exit 0;
78 0         0 } else {
79             die "fork failed: $!";
80             }
81             }
82              
83 2     2 1 10 sub stop {
84             my $self = shift;
85 2 50       17  
86 2 50       28 return unless defined $self->{pid};
87             return unless $self->{_my_pid} == $$;
88              
89             # This is a workaround for win32 fork emulation's bug.
90             #
91             # kill is inherently unsafe for pseudo-processes in Windows
92             # and the process calling kill(9, $pid) may be destabilized
93             # The call to Sleep will decrease the frequency of this problems
94             #
95             # SEE ALSO:
96             # http://www.gossamer-threads.com/lists/perl/porters/261805
97 2 50       18 # https://rt.cpan.org/Ticket/Display.html?id=67292
98             Win32::Sleep(0) if $^O eq "MSWin32"; # will relinquish the remainder of its time slice
99 2         73  
100             kill $TERMSIG => $self->{pid};
101 2 50       15  
102             Win32::Sleep(0) if $^O eq "MSWin32"; # will relinquish the remainder of its time slice
103              
104 2         24  
105 2         8 local $?; # waitpid modifies original $?.
106 4         2034552 LOOP: while (1) {
107 4 50       63 my $kid = waitpid( $self->{pid}, 0 );
108 4 50       36 if ($^O ne 'MSWin32') { # i'm not in hell
109 0         0 if (POSIX::WIFSIGNALED($?)) {
110 0 0       0 my $signame = (split(' ', $Config{sig_name}))[POSIX::WTERMSIG($?)];
111 0         0 if ($signame =~ /^(ABRT|PIPE)$/) {
112             Test::More::diag("your server received SIG$signame");
113             }
114             }
115 4 100 66     70 }
116 2         10 if ($kid == 0 || $kid == -1) {
117             last LOOP;
118             }
119 2         538 }
120             undef $self->{pid};
121             }
122              
123 2     2   415200 sub DESTROY {
124 2         11 my $self = shift;
125 2         11 local $@;
126             $self->stop();
127             }
128              
129             1;
130             __END__