File Coverage

blib/lib/Test/HTTP/Server/Simple.pm
Criterion Covered Total %
statement 68 79 86.0
branch 16 24 66.6
condition 4 6 66.6
subroutine 11 12 91.6
pod 3 3 100.0
total 102 124 82.2


line stmt bran cond sub pod time code
1             package Test::HTTP::Server::Simple;
2              
3             our $VERSION = '0.11';
4              
5 3     3   159986 use warnings;
  3         6  
  3         107  
6 3     3   16 use strict;
  3         6  
  3         105  
7 3     3   14 use Carp;
  3         10  
  3         208  
8              
9 3     3   4468 use NEXT;
  3         18463  
  3         82  
10              
11 3     3   23 use Test::Builder;
  3         3  
  3         180  
12             my $Tester = Test::Builder->new;
13              
14 3     3   14 use constant WIN32 => $^O =~ /win32/i;
  3         10  
  3         799  
15              
16             my $Event; # used on win32 only
17             if (WIN32) {
18             require Win32::Event;
19             $Event = Win32::Event->new();
20             }
21              
22             =head1 NAME
23              
24             Test::HTTP::Server::Simple - Test::More functions for HTTP::Server::Simple
25              
26              
27             =head1 SYNOPSIS
28              
29             package My::WebServer;
30             use base qw/Test::HTTP::Server::Simple HTTP::Server::Simple/;
31            
32             package main;
33             use Test::More tests => 42;
34            
35             my $s = My::WebServer->new;
36              
37             my $url_root = $s->started_ok("start up my web server);
38              
39             # connect to "$url_root/cool/site" and test with Test::WWW::Mechanize,
40             # Test::HTML::Tidy, etc
41              
42            
43             =head1 DESCRIPTION
44              
45             This mixin class provides methods to test an L-based web
46             server. Currently, it provides only one such method: C.
47              
48             =head2 started_ok [$text]
49              
50             C takes
51             an optional test description. The server needs to have been configured (specifically,
52             its port needs to have been set), but it should not have been run or backgrounded.
53             C calls C on the server, which forks it to run in the background.
54             L takes care of killing the server when your test script dies,
55             even if you kill your test script with an interrupt. C returns the URL
56             C which you can use to connect to your server.
57              
58             Note that if the child process dies, or never gets around to listening for connections, this
59             just hangs. (This may be fixed in a future version.)
60              
61             Also, it probably won't work if you use a custom L in your server.
62              
63             =cut
64              
65             my @CHILD_PIDS;
66              
67             # If an interrupt kills perl, END blocks are not run. This
68             # essentially converts interrupts (like CTRL-C) into a standard
69             # perl exit (even if we're inside an eval {}).
70             $SIG{INT} = sub { exit };
71              
72             # In case the surrounding 'prove' or similar harness got the SIGINT
73             # before we did, and hence STDERR is closed.
74             $SIG{PIPE} = 'IGNORE';
75              
76             END {
77 3     3   1933 local $?;
78 3 50       131 if (WIN32) {
79             # INT won't do since the server is doing a blocking read
80             # which isn't interrupted by anything but KILL on win32.
81 0         0 kill 9, $_ for @CHILD_PIDS;
82 0         0 sleep 1;
83 0         0 foreach (@CHILD_PIDS) {
84 0         0 sleep 1 while kill 0, $_;
85             }
86             }
87             else {
88 3         14 @CHILD_PIDS = grep {kill 0, $_} @CHILD_PIDS;
  3         50  
89 3 100       26 if (@CHILD_PIDS) {
90 2         60 kill 'USR1', @CHILD_PIDS;
91             local $SIG{ALRM} = sub {
92 3     3   3567 use POSIX ":sys_wait_h";
  3         25398  
  3         19  
93 0         0 my @last_chance = grep { waitpid($_, WNOHANG) == -1 }
  0         0  
94 0         0 grep { kill 0, $_ } @CHILD_PIDS;
95 0 0       0 die 'uncleaned Test::HTTP::Server::Simple processes: '.join(',',@last_chance)
96             if @last_chance;
97 2         61 };
98 2         39 alarm(5);
99 2         22 eval {
100 2         6 my $pid;
101 2   66     3526 @CHILD_PIDS = grep {$_ != $pid} @CHILD_PIDS
  3   66     228775  
102             while $pid = wait and $pid > 0 and @CHILD_PIDS;
103 2 50       21 @CHILD_PIDS = () if $pid == -1;
104             };
105 2 50       7 die $@ if $@;
106 2         86 alarm(0);
107             }
108             }
109             }
110              
111             sub started_ok {
112 8     8 1 8326 my $self = shift;
113 8         16 my $text = shift;
114 8 100       260 $text = 'started server' unless defined $text;
115              
116 8         24 my $port = $self->port;
117 8         42 my $pid;
118              
119 8         38 $self->{'test_http_server_simple_parent_pid'} = $$;
120              
121 8         12 my $child_loaded_yet = 0;
122              
123             # So this is a little complicated. The following signal handler does two
124             # ENTIRELY DIFFERENT things:
125             #
126             # In the parent, it just sets $child_loaded_yet, which breaks out of the
127             # while loop below. It's activated by the kid sending it a SIGUSR1 after
128             # it runs setup_listener
129             #
130             # In the kid, it sets the variable, but that's basically pointless since
131             # the call to ->background doesn't actually return in the kid. But also,
132             # it exits. And when you actually exit with 'exit' (as opposed to being
133             # killed by a signal) END blocks get run. Which means that you can use
134             # Devel::Cover to test the kid's coverage. This one is activated by the
135             # parent's END block in this file.
136              
137 8         16 local %SIG;
138 8 50       42 if (not WIN32) {
139 4 100   4   3095 $SIG{'USR1'} = sub { $child_loaded_yet = 1; exit unless $self->{'test_http_server_simple_parent_pid'} == $$ }
  4         397  
140 8         318 }
141              
142             # XXX TODO FIXME should somehow not have the signal handler around in the
143             # kid
144             # Comment: How about if ($pid) { $SIG{'USR1'} = ... }?
145            
146 8         14 eval { $pid = $self->background; };
  8         44  
147              
148 7 100       4566 if ($@) {
149 2         4 my $error_text = $@; # In case the next line changes it.
150 2         12 $Tester->ok(0, $text);
151 2         1140 $Tester->diag("HTTP::Server::Simple->background failed: $error_text");
152 2         116 return;
153             }
154              
155 5 100       176 unless ($pid =~ /^-?\d+$/) {
156 2         8 $Tester->ok(0, $text);
157 2         800 $Tester->diag("HTTP::Server::Simple->background didn't return a valid PID");
158 2         112 return;
159             }
160              
161 3         140 push @CHILD_PIDS, $pid;
162              
163 3 50       190 if (WIN32) {
164 0         0 $Event->wait();
165             }
166             else {
167 3         21278 1 while not $child_loaded_yet;
168             }
169              
170 3         144 $Tester->ok(1, $text);
171              
172 3         2529 return "http://localhost:$port";
173             }
174              
175             =begin private
176              
177             =head2 setup_listener
178              
179             We send a signal to the parent here. We need to use NEXT because this is a mixin.
180              
181             =end private
182              
183             =cut
184              
185             sub setup_listener {
186 1     1 1 2728 my $self = shift;
187 1         313 $self->NEXT::setup_listener;
188 1 50       5271 if (WIN32) {
189 0         0 $Event->pulse();
190             }
191             else {
192 1         59 kill 'USR1', $self->{'test_http_server_simple_parent_pid'};
193             }
194             }
195              
196             =head2 pids
197              
198             Returns the PIDs of the processes which have been started. Since
199             multiple test servers can be running at one, be aware that this
200             returns a list.
201              
202             =cut
203              
204             sub pids {
205 0     0 1   return @CHILD_PIDS;
206             }
207              
208             =head1 DEPENDENCIES
209              
210             L, L, L.
211              
212              
213             =head1 INCOMPATIBILITIES
214              
215             None reported.
216              
217              
218             =head1 BUGS AND LIMITATIONS
219              
220             Installs an interrupt signal handler, which may override any that another part
221             of your program has installed.
222              
223             Please report any bugs or feature requests to
224             C, or through the web interface at
225             L.
226              
227              
228             =head1 AUTHOR
229              
230             David Glasser C<< >>
231              
232              
233             =head1 LICENCE AND COPYRIGHT
234              
235             Copyright (c) 2005, Best Practical Solutions, LLC. All rights reserved.
236              
237             This module is free software; you can redistribute it and/or
238             modify it under the same terms as Perl itself. See L.
239              
240              
241             =head1 DISCLAIMER OF WARRANTY
242              
243             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
244             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
245             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
246             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
247             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
248             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
249             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
250             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
251             NECESSARY SERVICING, REPAIR, OR CORRECTION.
252              
253             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
254             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
255             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
256             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
257             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
258             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
259             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
260             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
261             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
262             SUCH DAMAGES.
263              
264             =cut
265              
266             1;
267