File Coverage

blib/lib/Test/WWW/Mechanize/HSS.pm
Criterion Covered Total %
statement 83 89 93.2
branch 22 40 55.0
condition 3 6 50.0
subroutine 13 14 92.8
pod 1 4 25.0
total 122 153 79.7


line stmt bran cond sub pod time code
1             package Test::WWW::Mechanize::HSS;
2 8     8   7060 use strict;
  8         17  
  8         336  
3 8     8   1894 use parent 'Test::WWW::Mechanize';
  8         862  
  8         61  
4 8     8   1577707 use vars qw($VERSION);
  8         24  
  8         576  
5             $VERSION = '0.02';
6              
7             =head1 NAME
8              
9             Test::WWW::Mechanize::HSS - Test HTTP::Server::Simple programs using WWW::Mechanize
10              
11             =head1 SYNOPSIS
12              
13             use Test::WWW::Mechanize::HSS;
14             use MyApp::Server; # A descendant from HTTP::Server::Simple
15              
16             # Construct your server
17             my $s = MyApp::Server->new(
18             ...
19             );
20              
21             my $mech = Test::WWW::Mechanize::HSS->new(
22             server => $s
23             );
24            
25             $mech->get_ok('/');
26              
27             =head1 ABSTRACT
28              
29             This module implements the necessary glue to run code written for
30             L and L
31             using L without needing
32             to fire up an actual webserver.
33              
34             =head1 STATUS
35              
36             This is an early release, hacked together to test
37             one of my applications. So far it has worked well
38             for me, but there sure are some corners that
39             I haven't tested well. Tests and patches
40             are welcome.
41              
42             =cut
43              
44 8     8   49 use URI;
  8         18  
  8         183  
45 8     8   49 use HTTP::Request;
  8         16  
  8         175  
46 8     8   44 use HTTP::Response;
  8         18  
  8         9577  
47              
48 9     9 0 130 sub server { $_[0]->{server} };
49 0 0   0 0 0 sub host { $_[1] ? $_[0]->{host} = $_[1] : $_[0] };
50 9     9 0 86 sub has_host { exists $_[0]->{host} };
51              
52             sub new {
53 7     7 1 6081 my ($class,%args) = @_;
54              
55 7         26 my $s = delete $args{server};
56 7         73 my $self = $class->SUPER::new(%args);
57 7         131829 $self->{server} = $s;
58            
59 7 50       224 $s->after_setup_listener if $s->can('after_setup_listener');
60            
61             # Save our known good environment
62 7         343 HTTP::Server::Simple::CGI::Environment->setup_environment;
63              
64 7         525 $self
65             };
66              
67             sub _make_request {
68 9     9   110866 my ($self,$request) = @_;
69              
70 9         47 my $response = $self->_do_hssimple_request($request);
71            
72 9         60 $response->header( 'Content-Base', $request->uri );
73 9         739 $response->request($request);
74 9 50       112 if ( $request->uri->as_string =~ m{^/} ) {
75 0         0 $request->uri(
76             URI->new( 'http://localhost:80/' . $request->uri->as_string ) );
77             }
78 9 50       193 $self->cookie_jar->extract_cookies($response) if $self->cookie_jar;
79              
80             # check if that was a redirect
81 9 100 66     2083 if ( $response->header('Location')
82             && $self->redirect_ok( $request, $response ) )
83             {
84 1         118 my $old_response = $response;
85              
86             # *where* do they want us to redirect to?
87 1         4 my $location = $old_response->header('Location');
88              
89             # no-one *should* be returning relative URLs, but if they
90             # are then we'd better cope with it. Let's create a new URI, using
91             # our request as the base.
92 1         31 my $uri = URI->new_abs( $location, $request->uri )->as_string;
93              
94             # make a new response, and save the old response in it
95 1         290 $response = $self->_make_request( HTTP::Request->new( GET => $uri ) );
96 1         2 my $end_of_chain = $response;
97 1         5 while ( $end_of_chain->previous ) # keep going till the end
98             {
99 0         0 $end_of_chain = $end_of_chain->previous;
100             } # of the chain...
101 1         11 $end_of_chain->previous($old_response); # ...and add us to it
102             } else {
103 8         333 $response->{_raw_content} = $response->content;
104             }
105              
106 9         212 return $response;
107             }
108              
109             sub _do_hssimple_request {
110 9     9   22 my ($self,$request) = @_;
111 9         33 my $uri = $request->uri;
112            
113 9 50       118 $uri->scheme('http') unless defined $uri->scheme;
114 9 50       417 $uri->host('localhost') unless defined $uri->host;
115 9 50       699 $self->cookie_jar->add_cookie_header($request)
116             if $self->cookie_jar;
117              
118 9 50       1838 unless ($request->header('Host')) {
119 9 50       342 my $host = $self->has_host
120             ? $self->host
121             : $uri->host;
122              
123 9         203 $request->header('Host', $host);
124             }
125              
126 9         469 my @creds = $self->get_basic_credentials( "Basic", $uri );
127 9 50       862 $request->authorization_basic( @creds ) if @creds;
128              
129             # Run a HTTP::Server::Simple::CGI request
130             # Currently neglects all the fancy features
131 9         76 my $rs = $request->content;
132 9 50   7   383 open my $rsh, '<', \$rs
  7         71  
  7         14  
  7         70  
133             or die "Couldn't create read-only memory file? $!";
134 9         10579 binmode $rsh;
135 9         40 local *STDIN = *$rsh;
136            
137 9 50       127 open my $STDOUT, '>', \my $stdout
138             or die "Open failed? $!";
139 9         64 local *STDOUT = $STDOUT;
140            
141             #warn "<<<$rs>>>";
142            
143 9         52 my $s = $self->server;
144            
145 9         139 $s->stdio_handle($STDOUT);
146              
147 9 50       193 $self->accept_hook() if $self->can("accept_hook");
148              
149 9 100       43 my ( $method, $request_uri, $proto ) = (
150             $request->method,
151             $request->uri->query
152             ? $request->uri->path . '?' . $request->uri->query
153             : $request->uri->path,
154             "HTTP/1.1"
155             );
156            
157             # cut-n-paste from HTTP::Server::Simple::_process_request
158 9 50       531 unless ($s->valid_http_method($method) ) {
159 0         0 $s->bad_request;
160 0         0 goto REQUEST_DONE;
161             }
162              
163             #$proto ||= "HTTP/0.9";
164              
165 9         139 my ( $file, $query_string )
166             = ( $request_uri =~ /([^?]*)(?:\?(.*))?/s ); # split at ?
167              
168 9 100       107 $s->setup(
169             method => $method,
170             protocol => $proto,
171             query_string => ( defined($query_string) ? $query_string : '' ),
172             request_uri => $request_uri,
173             path => $file,
174             localname => $s->host,
175             localport => $s->port,
176             peername => 'testing',
177             peeraddr => '127.0.0.1',
178             );
179              
180             # HTTP/0.9 didn't have any headers (I think)
181 9 50 33     1067 if ( $proto =~ m{HTTP/(\d(\.\d)?)$} and $1 >= 1 ) {
182 9         199 my $headers = [];
183 9     22   106 $request->headers->scan( sub { push @$headers, @_ });
  22         481  
184              
185 9         133 $s->headers($headers);
186             }
187              
188 9 50       619 $s->post_setup_hook if $s->can("post_setup_hook");
189            
190 9         933071 my $ok = eval {
191 9         117 $s->handler;
192 9         41598 1
193             };
194 9         27 my $err = $@;
195 9         20 REQUEST_DONE:
196            
197             #warn "[[[$stdout]]]";
198             my $response;
199 9 50       41 if ($ok) {
200 9         107 $response = HTTP::Response->parse($stdout);
201             } else {
202 0         0 $response = HTTP::Response->new(500, $err, ['X-Internal','Internal error'], $err);
203             };
204 9         2118 return $response
205             };
206              
207             1;
208              
209             __END__