File Coverage

inc/Test/TCP.pm
Criterion Covered Total %
statement 15 17 88.2
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 21 23 91.3


line stmt bran cond sub pod time code
1             #line 1
2 4     4   1359 package Test::TCP;
  4         4  
  4         91  
3 4     4   12 use strict;
  4         3  
  4         70  
4 4     4   68 use warnings;
  4         8  
5             use 5.00800;
6 4         30 our $VERSION = '0.02';
7             use Sub::Exporter -setup => {
8             exports => [
9             qw/ empty_port test_tcp wait_port /
10             ],
11 4     4   2161 groups => { default => [':all'] }
  4         35134  
12 4     4   2569 };
  4         9  
  4         17  
13 4     4   3410 use IO::Socket::INET;
  0            
  0            
14             use Params::Validate ':all';
15              
16             sub empty_port {
17             my $port = shift || 10000;
18             $port = 19000 unless $port =~ /^[0-9]+$/ && $port < 19000;
19              
20             while ( $port++ < 20000 ) {
21             my $sock = IO::Socket::INET->new(
22             Listen => 5,
23             LocalAddr => '127.0.0.1',
24             LocalPort => $port,
25             Proto => 'tcp'
26             );
27             return $port if $sock;
28             }
29             die "empty port not found";
30             }
31              
32             sub test_tcp {
33             my %args = validate(@_, {
34             client => CODEREF,
35             server => CODEREF,
36             port => {
37             type => SCALAR,
38             default => empty_port(),
39             },
40             });
41              
42             my $port = $args{port};
43              
44             if ( my $pid = fork() ) {
45             # parent.
46             wait_port($port);
47              
48             $args{client}->($port);
49              
50             kill TERM => $pid;
51             waitpid( $pid, 0 );
52             }
53             elsif ( $pid == 0 ) {
54             # child
55             $args{server}->($port);
56             }
57             else {
58             die "fork failed: $!";
59             }
60             }
61              
62             sub _check_port {
63             my ($port) = @_;
64              
65             my $remote = IO::Socket::INET->new(
66             Proto => 'tcp',
67             PeerAddr => '127.0.0.1',
68             PeerPort => $port,
69             );
70             if ($remote) {
71             close $remote;
72             return 1;
73             }
74             else {
75             return 0;
76             }
77             }
78              
79             sub wait_port {
80             my $port = shift;
81              
82             my $retry = 10;
83             while ( $retry-- ) {
84             return if _check_port($port);
85             sleep 1;
86             }
87             die "cannot open port: $port";
88             }
89              
90             1;
91             __END__