File Coverage

blib/lib/Test/PayProp/API/Public/Emulator.pm
Criterion Covered Total %
statement 44 47 93.6
branch 10 14 71.4
condition 2 3 66.6
subroutine 11 11 100.0
pod 1 4 25.0
total 68 79 86.0


line stmt bran cond sub pod time code
1             package Test::PayProp::API::Public::Emulator;
2              
3 23     23   3949201 use strict;
  23         46  
  23         724  
4 23     23   96 use warnings;
  23         63  
  23         899  
5              
6 23     23   9036 use Mouse;
  23         584948  
  23         97  
7 23     23   21447 use Parallel::ForkManager;
  23         1883538  
  23         1767  
8 23     23   228 use Time::HiRes qw/ gettimeofday tv_interval usleep /;
  23         57  
  23         262  
9 23     23   72748 use IO::Socket::INET;
  23         344836  
  23         195  
10 23     23   13290 use POSIX qw( :sys_wait_h );
  23         88  
  23         309  
11              
12             has [ qw/exec scheme host/ ] => (
13             is => 'rw',
14             isa => 'Value',
15             required => 1,
16             );
17              
18             has [ qw/argv/ ] => (
19             is => 'rw',
20             isa => 'Str',
21             required => 0,
22             default => sub { '' },
23             );
24              
25             has [ qw/argv_second/ ] => (
26             is => 'rw',
27             isa => 'Str',
28             required => 0,
29             default => sub { '' },
30             );
31              
32             has [ qw/pid/ ] => (
33             is => 'rw',
34             isa => 'Int',
35             );
36              
37             has [ qw/port/ ] => (
38             is => 'rw',
39             isa => 'Int',
40             default => sub {
41             # avoid clashing with any other test running an emulator at the same time
42             my $port = 6450 + $$ % 100;
43             $ENV{EMULATOR_PORT} = $port;
44             return $port;
45             },
46             );
47              
48             has 'path' => (
49             is => 'rw',
50             isa => 'Str',
51             default => sub { 't/emulation/' },
52             );
53              
54             has 'pm' => (
55             is => 'rw',
56             isa => 'Parallel::ForkManager',
57             lazy => 1,
58             default => sub {
59             return Parallel::ForkManager->new( 2 );
60             },
61             );
62              
63             sub url {
64 45     45 0 1242 my ( $self ) = @_;
65 45         683 return $self->scheme . "://" . $self->host . ":" . $self->port;
66             }
67              
68             sub start {
69 59     59 0 109000 my ( $self ) = @_;
70              
71 59 100       698 if (my $pid = $self->pm->start) {
72 43         346314 $self->pid( $pid );
73             }
74             else {
75 16 50       166771 my @command = (
76             $^X,
77             $self->path . $self->exec,
78             "daemon",
79             "-l",
80             $self->scheme . "://*:" . $self->port,
81             $self->argv,
82             ( $self->argv_second ? ( $self->argv_second ) : () ),
83             );
84              
85 16         1194 main::note( "EMULATOR: " . join( " ",@command ) );
86 16         0 exec( @command );
87             }
88              
89             # give emulator time to start up:
90 43         1098 my $timeout = 10;
91 43         1518 my @t = gettimeofday;
92 43         361 while () {
93 208 50       11496 die "Process @{[ $self->pid ]} terminated"
  0         0  
94             if waitpid $self->pid, WNOHANG;
95              
96             # Sleep up-front because a previous server may still be closing down
97 208         104075584 usleep 500_000;
98              
99 208 50       5873 if (tv_interval(\@t) > $timeout) {
100 0         0 $self->stop;
101 0         0 die "Emulator didn't come up within $timeout seconds";
102             }
103              
104 208         20148 my $sock = IO::Socket::INET->new(
105             Proto => 'tcp',
106             PeerHost => '127.0.0.1',
107             PeerPort => $self->port,
108             );
109 208 100 66     205663 last if $sock && $sock->connected;
110             }
111              
112 43         3908 return $self->pid;
113             }
114              
115             sub stop {
116 50     50 0 403343 my ( $self ) = @_;
117 50 50       1027 $self->pm->finish if $self->pm;
118              
119 50 100       4690 if ( $self->pid ) {
120 49         4717 kill( 'HUP',$self->pid );
121             }
122             }
123              
124             sub DEMOLISH {
125              
126 7     7 1 13966 my ( $self ) = @_;
127 7         45 $self->stop;
128             }
129              
130             __PACKAGE__->meta->make_immutable;