File Coverage

blib/lib/Net/Respite/Server/Test.pm
Criterion Covered Total %
statement 67 75 89.3
branch 18 36 50.0
condition 9 26 34.6
subroutine 9 9 100.0
pod 0 1 0.0
total 103 147 70.0


line stmt bran cond sub pod time code
1             package Net::Respite::Server::Test;
2              
3 4     4   319015 use strict;
  4         10  
  4         157  
4 4     4   22 use warnings;
  4         8  
  4         199  
5 4     4   22 use Test::More;
  4         4  
  4         70  
6 4     4   4838 use File::Temp;
  4         80584  
  4         356  
7 4     4   1185 use Throw qw(throw import);
  4         10940  
  4         28  
8 4     4   235 use Time::HiRes qw(sleep);
  4         9  
  4         36  
9 4     4   2105 use End;
  4         1632  
  4         4996  
10             #use Data::Debug;
11              
12             sub setup_test_server {
13 5   50 5 0 199600 my $args = shift || {};
14 5 50       22 my $verbose = exists($args->{'verbose'}) ? $args->{'verbose'} : 1;
15              
16             # setup some defaults
17 5   33     31 my $port = $args->{'port'} || do {
18             require IO::Socket;
19             my $sock = IO::Socket::INET->new;
20             $sock->configure({
21             LocalPort => 0,
22             Listen => 1,
23             Proto => 'tcp',
24             ReuseAddr => 1,
25             }) || throw "Could not create temp socket", {msg => $!};
26             my $port = $sock->sockport || throw "Could not generate random usable sockport";
27             };
28 5         334 my $tmpnam = File::Temp->new;
29 5   33     3709 my $pid_file = $args->{'pid_file'} || "$tmpnam.$$.pid";
30 5   33     99 my $access_file = $args->{'access_file'} || "$tmpnam.$$.access";
31 5   33     65 my $error_file = $args->{'error_file'} || "$tmpnam.$$.error";
32 5         50 undef $tmpnam;
33 5 50       4843 my $no_brand = exists($args->{'no_brand'}) ? 1 : 0;
34 5 50       13 my $no_ssl = exists($args->{'no_ssl'}) ? 1 : 0;
35             #$no_ssl = 1;
36 5 50       25 my $flat = exists($args->{'flat'}) ? 1 : 0;
37              
38 5   33     28 my $server = $args->{'server'} || do {
39             my $pkg = $args->{'server_class'} || 'Net::Respite::Server';
40             (my $file = "$pkg.pm") =~ s|::|/|g;
41             eval { require $file } || throw "Could not require client library", {msg => $@};
42             $pkg->new({
43             no_brand => $no_brand,
44             ($args->{'service'} ? (server_name => $args->{'service'}) : ()),
45             ($args->{'api_meta'} ? (api_meta => $args->{'api_meta'}) : ()),
46             port => $port,
47             server_type => $args->{'server_type'} || 'Fork',
48             no_ssl => $no_ssl,
49             flat => $flat,
50             host => $args->{'host'} || 'localhost',
51             pass => $args->{'pass'},
52             pid_file => $pid_file,
53             access_log_file => $access_file,
54             log_file => $error_file,
55             user => defined($args->{'user'}) ? $args->{'user'} : $<,
56             group => defined($args->{'group'}) ? $args->{'group'} : $(,
57             });
58             };
59             #debug $server;
60 5         66 my $service = $server->server_name;
61 5         13 $service =~ s/_server$//;
62              
63 5 50       30 my $encoded = exists($args->{'utf8_encoded'}) ? 1 : 0;
64 5   33     28 my $client = $args->{'client'} || do {
65             my $pkg = $args->{'client_class'} || 'Net::Respite::Client';
66             (my $file = "$pkg.pm") =~ s|::|/|g;
67             eval { require $file } || throw "Could not require client library", {msg => $@};
68             $pkg->new({
69             no_brand => $no_brand,
70             service => $service,
71             port => $port,
72             host => $server->{'host'},
73             pass => $args->{'pass'},
74             no_ssl => $no_ssl,
75             flat => $flat,
76             utf8_encoded => $encoded,
77             ($args->{'brand'} ? (brand => $args->{'brand'}) : ()),
78             });
79             };
80             #debug $client;
81              
82             ###----------------------------------------------------------------###
83             # start the server in a child, block the parent until ready
84              
85 5         15887 my $pid = fork;
86 5 50       630 die "Could not fork during test\n" if ! defined $pid;
87 5 100       363 if (!$pid) { # child
88 2         609 local @ARGV;
89 2         245 $server->run_server(setsid => 0, background => 0); # allow a kill term to close the server too
90 0         0 exit;
91             }
92              
93 3         135 my $client_pid = $$;
94             $client->{'_test_ender'} = end {
95 3     3   8483 diag("Client object ending: pid=[$$] port=[$port]");
96              
97 3 50       4237 if ($client_pid != $$) {
98 0         0 diag("ORIGPID[$client_pid]!=CURRPID[$$] Refusing to stop server on port [$port]! Running setup_test_server() while an old client object still exists can trigger this phantom cleanup on the OLD client object when the child request from the NEW server completes, especially for the Fork personality.");
99 0         0 return;
100             }
101              
102 3 50       16 diag("Process list") if $verbose;
103 3         9242 $server->__ps;
104              
105 3         71 diag("Stop server");
106 3         4108 $server->__stop;
107             # get some info - then tear down
108              
109 3 50       51 diag("Tail of the error_log") if $verbose;
110 3 50       4228 $server->__tail_error(1000) if $verbose;
111              
112 3 50       114 diag("Tail of the access_log") if $verbose;
113 3 50 50     5083 $server->__tail_access($server->{'tail_access'} || 20) if $verbose;
114              
115 3 50       129 diag("Shut down server") if $verbose;
116 3         9405 unlink $_ for $pid_file, $access_file, $error_file; # double check
117 3         949 };
118              
119             # block the parent (that will run client tests) until the child running the server is fully setup
120 3         348 my $connected;
121 3         129 for (1 .. 30) {
122 3         301990 sleep 0.1;
123 3         67 my $class = 'IO::Socket::INET';
124 3 50       92 if (!$no_ssl) {
125 0         0 require IO::Socket::SSL;
126 0         0 $class = 'IO::Socket::SSL';
127             }
128 3   50     204 my $sock = $class->new(PeerHost => "localhost", PeerPort => $port, SSL_verify_mode => 0) || next;
129 3         4648 print $sock "GET /waited_until_child HTTP/1.0\n\n";
130 3         40 $connected = 1;
131 3         131 last;
132             }
133 3 50       49 if (! $connected) {
134 0         0 diag("Tail of the error_log");
135 0 0 0     0 $server->__tail_error($server->{'tail_error'} || 20) if $verbose;
136 0         0 die "Failed to connect to the server: $!";
137             }
138              
139 3 50       139 return wantarray ? ($client, $server) : $client;
140             }
141              
142             1;
143              
144             __END__