File Coverage

inc/Test/HTTP/LocalServer.pm
Criterion Covered Total %
statement 31 82 37.8
branch 0 20 0.0
condition 0 5 0.0
subroutine 11 19 57.8
pod 6 6 100.0
total 48 132 36.3


line stmt bran cond sub pod time code
1             package Test::HTTP::LocalServer;
2              
3             # start a fake webserver, fork, and connect to ourselves
4 11     11   39167 use strict;
  11         17  
  11         352  
5             # this has to happen here because LWP::Simple creates a $ua
6             # on load so any time after this is too late.
7             BEGIN {
8 11     11   266 delete @ENV{qw(
9             HTTP_PROXY http_proxy CGI_HTTP_PROXY
10             HTTPS_PROXY https_proxy HTTP_PROXY_ALL http_proxy_all
11             )};
12             }
13 11     11   3909 use LWP::Simple;
  11         136605  
  11         65  
14 11     11   6838 use FindBin;
  11         7720  
  11         368  
15 11     11   48 use File::Spec;
  11         13  
  11         129  
16 11     11   6772 use File::Temp;
  11         139081  
  11         683  
17 11     11   3961 use URI::URL qw();
  11         21208  
  11         239  
18 11     11   48 use Carp qw(carp croak);
  11         12  
  11         471  
19              
20 11     11   38 use vars qw($VERSION);
  11         14  
  11         5658  
21             $VERSION = '0.56';
22              
23             =head1 SYNOPSIS
24              
25             use LWP::Simple qw(get);
26             my $server = Test::HTTP::LocalServer->spawn;
27              
28             ok get $server->url, "Retrieve " . $server->url;
29              
30             $server->stop;
31              
32             =head1 METHODS
33              
34             =head2 Cspawn %ARGS>
35              
36             This spawns a new HTTP server. The server will stay running until
37             $server->stop
38             is called.
39              
40             Valid arguments are :
41              
42             =over 4
43              
44             =item *
45              
46             C<< html => >> scalar containing the page to be served
47              
48             =item *
49              
50             C<< file => >> filename containing the page to be served
51              
52             =item *
53              
54             C<< debug => 1 >> to make the spawned server output debug information
55              
56             =item *
57              
58             C<< eval => >> string that will get evaluated per request in the server
59              
60             Try to avoid characters that are special to the shell, especially quotes.
61             A good idea for a slow server would be
62              
63             eval => sleep+10
64              
65             =back
66              
67             All served HTML will have the first %s replaced by the current location.
68              
69             The following entries will be removed from C<%ENV>:
70              
71             HTTP_PROXY
72             http_proxy
73             CGI_HTTP_PROXY
74              
75             =cut
76              
77             sub spawn {
78 0     0 1   my ($class,%args) = @_;
79 0           my $self = { %args };
80 0           bless $self,$class;
81              
82 0           local $ENV{TEST_HTTP_VERBOSE};
83             $ENV{TEST_HTTP_VERBOSE}= 1
84 0 0         if (delete $args{debug});
85              
86 0           $self->{delete} = [];
87 0 0         if (my $html = delete $args{html}) {
88             # write the html to a temp file
89 0           my ($fh,$tempfile) = File::Temp::tempfile();
90 0           binmode $fh;
91 0 0         print $fh $html
92             or die "Couldn't write tempfile $tempfile : $!";
93 0           close $fh;
94 0           push @{$self->{delete}},$tempfile;
  0            
95 0           $args{file} = $tempfile;
96             };
97 0           my ($fh,$logfile) = File::Temp::tempfile();
98 0           close $fh;
99 0           push @{$self->{delete}},$logfile;
  0            
100 0           $self->{logfile} = $logfile;
101 0   0       my $web_page = delete $args{file} || "";
102              
103 0           my $server_file = File::Spec->catfile( $FindBin::Bin,File::Spec->updir,'inc','Test','HTTP','log-server' );
104 0           my @opts;
105             push @opts, "-e" => qq{"} . delete($args{ eval }) . qq{"}
106 0 0         if $args{ eval };
107              
108 0           my $cmd= qq'$^X "$server_file" "$web_page" "$logfile" @opts|';
109             #warn "[$cmd]";
110 0 0         my $pid = open my $server, $cmd
111             or croak "Couldn't spawn local server $server_file : $!";
112 0           my $url = <$server>;
113 0           chomp $url;
114 0 0         die "Couldn't read back local server url"
115             unless $url;
116              
117 0           $self->{_fh} = $server;
118 0           $self->{_pid} = $pid;
119 0           $self->{_server_url} = URI::URL->new($url);
120              
121 0           $self;
122             };
123              
124             =head2 C<< $server->port >>
125              
126             This returns the port of the current server. As new instances
127             will most likely run under a different port, this is convenient
128             if you need to compare results from two runs.
129              
130             =cut
131              
132             sub port {
133 0 0   0 1   carp __PACKAGE__ . "::port called without a server" unless $_[0]->{_server_url};
134             $_[0]->{_server_url}->port
135 0           };
136              
137             =head2 C<< $server->url >>
138              
139             This returns the url where you can contact the server. This url
140             is valid until the C<$server> goes out of scope or you call
141             $server->stop;
142              
143             =cut
144              
145             sub url {
146             $_[0]->{_server_url}->abs
147 0     0 1   };
148              
149             =head2 C<< $server->stop >>
150              
151             This stops the server process by requesting a special
152             url.
153              
154             =cut
155              
156             sub stop {
157 0     0 1   get( $_[0]->{_server_url} . "quit_server" );
158 0           close $_[0]->{_fh};
159             undef $_[0]->{_server_url}
160 0           };
161              
162             =head2 C<< $server->kill >>
163              
164             This kills the server process via C. The log
165             cannot be retrieved then.
166              
167             =cut
168              
169             sub kill {
170 0     0 1   CORE::kill( 9 => $_[0]->{ _pid } );
171 0           undef $_[0]->{_server_url};
172 0           undef $_[0]->{_pid};
173             };
174              
175             =head2 C<< $server->get_log >>
176              
177             This returns the
178             output of the server process. This output will be a list of
179             all requests made to the server concatenated together
180             as a string.
181              
182             =cut
183              
184             sub get_log {
185 0     0 1   my ($self) = @_;
186 0           return get( $self->{_server_url} . "get_server_log" );
187             };
188              
189             sub DESTROY {
190 0 0   0     $_[0]->stop if $_[0]->{_server_url};
191 0           for my $file (@{$_[0]->{delete}}) {
  0            
192 0 0         unlink $file or warn "Couldn't remove tempfile $file : $!\n";
193             };
194 0 0 0       if( $_[0]->{_pid } and CORE::kill( 0 => $_[0]->{_pid })) {
195 0           $_[0]->kill; # boom
196             };
197             };
198              
199             =head1 URLs implemented by the server
200              
201             =head2 302 redirect C<< $server->redirect($target) >>
202              
203             This URL will issue a redirect to C<$target>. No special care is taken
204             towards URL-decoding C<$target> as not to complicate the server code.
205             You need to be wary about issuing requests with escaped URL parameters.
206              
207             =head2 404 error C<< $server->error_notfound($target) >>
208              
209             This URL will response with status code 404.
210              
211             =head2 Timeout C<< $server->error_timeout($seconds) >>
212              
213             This URL will send a 599 error after C<$seconds> seconds.
214              
215             =head2 Timeout+close C<< $server->error_close($seconds) >>
216              
217             This URL will send nothing and close the connection after C<$seconds> seconds.
218              
219             =head2 Error in response content C<< $server->error_after_headers >>
220              
221             This URL will send headers for a successfull response but will close the
222             socket with an error after 2 blocks of 16 spaces have been sent.
223              
224             =head2 Chunked response C<< $server->chunked >>
225              
226             This URL will return 5 blocks of 16 spaces at a rate of one block per second
227             in a chunked response.
228              
229             =head2 Other URLs
230              
231             All other URLs will echo back the cookies and query parameters.
232              
233             =cut
234              
235 11     11   48 use vars qw(%urls);
  11         12  
  11         616  
236             %urls = (
237             'redirect' => 'redirect/%s',
238             'error_notfound' => 'error/notfound/%s',
239             'error_timeout' => 'error/timeout/%s',
240             'error_close' => 'error/close/%s',
241             'error_after_headers' => 'error/after_headers',
242             'chunked' => 'chunks',
243             );
244             for (keys %urls) {
245 11     11   38 no strict 'refs';
  11         10  
  11         803  
246             my $name = $_;
247             *{ $name } = sub {
248 0     0     my $self = shift;
249 0           $self->url . sprintf $urls{ $name }, @_;
250             };
251             };
252              
253             =head1 EXPORT
254              
255             None by default.
256              
257             =head1 COPYRIGHT AND LICENSE
258              
259             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
260              
261             Copyright (C) 2003-2011 Max Maischein
262              
263             =head1 AUTHOR
264              
265             Max Maischein, Ecorion@cpan.orgE
266              
267             Please contact me if you find bugs or otherwise improve the module. More tests are also very welcome !
268              
269             =head1 SEE ALSO
270              
271             L,L,L
272              
273             =cut
274              
275             1;