Hello all. This is a long exposition, but the question at the end is short and salient. I hope here are some experts for the topical module.
I have a CGI program.
#!/usr/bin/perl -T use MyModule; MyModule->new->go;
As you can clearly see, the main code is contained in a module.
package MyModule; use CGI qw(); sub new { my $class = shift; my %self; bless \%self => $class; $self{cgi} = CGI->new; return \%self; } sub go { my $self = shift; if ($self->{cgi}->request_method eq 'POST') { print $self->{cgi} ->header(-Status => 201, -Location => $self->{cgi}->url,); print $self->{cgi}->param('POSTDATA'); } elsif (length $self->{cgi}->path_info > 1) { print $self->{cgi} ->header(-Status => 500, -Content_type => 'text/plain',); print "error"; } else { print $self->{cgi} ->header(-Status => 200, -Content_type => 'application/xml', +); print "<okay />"; } } 1;
I am supposed to test the functionality of the CGI program through the HTTP interface. That means I cannot simply load the module and mess with its methods. Those are all private, so to speak. The HTTP interface is public.
Writing tests for that is easy with LWP. Assume I ship my testing code with a dinky CGI-capable web server of my own instead of relying on the end-user having already set up Apache or something. HTTP::Server::Simple::CGI is the obvious choice for that. The test file looks like this:
#!/usr/bin/perl -T use Test::More tests => 8; use LWP::UserAgent qw(); require 'TestServer.pm'; my $pid = TestServer->new(12345)->background; my $ua = LWP::UserAgent->new; my $r; $r = $ua->request(HTTP::Request->new(GET => 'http://localhost:12345',) +); ok $r->is_success; like $r->header('Content-Type'), qr(^application/xml); $r = $ua->request(HTTP::Request->new(GET => 'http://localhost:12345/pathinfoblahblah',)); ok $r->is_error; like $r->header('Content-Type'), qr(^text/plain); is $r->content, 'error'; my $post_data = 'some post data'; $r = $ua->request(HTTP::Request->new(POST => 'http://localhost:12345', ['Content-Type' => 'application/octet-stream'], $post_data,)); is $r->code, 201; ok $r->header('Location'); is $r->content, $post_data; kill 'KILL', $pid;
The test file loads the test server module.
package TestServer; use HTTP::Server::Simple::CGI qw(); use parent 'HTTP::Server::Simple::CGI'; use MyModule; sub handler { MyModule->new->go; } 1;
This is how I thought it should work. But it does not. The tests fail. When I inspect the server response, the stuff that was printed to the CGI's STDOUT in MyModule ends up wholesale in the HTTP body! LWP makes up a makeshift HTTP header. (Side remark: Ostensibly, LWP speaks HTTP/1.1 to the server, it puzzles me why there's the 0.9 reply.)
diag $r->as_string; # HTTP/0.9 200 Assumed OK # Client-Date: Tue, 17 Feb 2009 01:39:37 GMT # Client-Peer: 127.0.0.1:12345 # Client-r-Num: 1 # # Status: 200 # Content-Type: application/xml # # <okay /> diag $r->as_string; # HTTP/0.9 200 Assumed OK # Client-Date: Tue, 17 Feb 2009 01:40:03 GMT # Client-Peer: 127.0.0.1:12345 # Client-r-Num: 1 # # Status: 500 # Content-Type: text/plain; charset=ISO-8859-1 # # error diag $r->as_string; # HTTP/0.9 200 Assumed OK # Client-Date: Tue, 17 Feb 2009 01:40:32 GMT # Client-Peer: 127.0.0.1:12345 # Client-r-Num: 1 # # Status: 201 # Location: http://localhost:12345 # Content-Type: text/html; charset=ISO-8859-1 # # some post data
The error lies clearly in TestServer, because when I modify the test program to interact with the CGI program on Apache, everything works. Additional observation (no idea whether this is significant): either CGI.pm when running under Apache or Apache itself turns the HTTP 'Status' header into the appropriate status line that is initial to each response, e.g. 'HTTP/1.1 200 OK'; this feature is missing from the interaction with HTTP::Server::Simple::CGI.
The question: how does TestServer need to be changed so that my tests pass?
In reply to problems with HTTP::Server::Simple::CGI by Anonymous Monk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |