NAME

Test::CGI::External - run tests on an external CGI program

SYNOPSIS

use Test::More;
use Test::CGI::External;

my $tester = Test::CGI::External->new ();

$tester->set_cgi_executable ("x.cgi");

my %options;

# Automatically tests

$tester->run (\%options);

# Test with a query

$options{REQUEST_METHOD} = 'GET';
$options{QUERY_STRING} = 'text="alcohol"';
$tester->run (\%options);

# Test compression of output

$tester->do_compression_test (1);
$tester->run (\%options);

# Print the plan.

$tester->plan ();

done_testing ();

After the test has run, the uncompressed output is in $options{body}.

DESCRIPTION

Test::CGI::External is a tool for running basic checks of the operation of a CGI (common gateway interface) program. It is meant to be used for "sanity checks" of CGI program operation. For example, if a CGI program prints stuff on standard output before it prints its HTTP headers, when running from behind a server, the only output visible from a browser is an obscure server error message.

In a Perl script,

use Test::More;
my $tester = Test::CGI::External->new ();
$tester->set_cgi_executable ('example.cgi');
$tester->run ({});
done_testing ();

The above tests whether

  • there is a program called example.cgi

  • the program example.cgi is executable (except on Windows)

  • when run, example.cgi produces a correct Content-Type header

  • when run, example.cgi does not print out ill-formed headers (for example, print debugging messages on standard output)

  • when run, example.cgi exits with a zero status

  • when run, example.cgi does not print any error messages

In other words, this tests for extremely simple "slip-up" mistakes and basic program execution.

Test::CGI::External runs CGI programs as stand-alone programs, under a faked CGI-like environment created by manipulating environment variables. Thus it does not require a web server. The tested CGI program can be in any language, not just Perl; Test::CGI::External is meant to test external programs which are completely independent of itself. Test::CGI::External was originally created to check the operation of CGI programs written in C.

Test::CGI::External is meant for the testing stage before the program is put onto a web server. One of the main errors this module catches for the author is stray printf statements. If a program with stray printf statements is uploaded to the web server and run as a CGI program, the browser will show only a 500 Server Error message. Another typical mistake is forgetting to make the CGI program executable; again, this results in a weird server error.

Test::CGI::External is TAP (Test Anything Protocol)-compliant and should work with Perl testing modules like Test::More.

METHODS

do_compression_test

$tester->do_compression_test (1);

Turn on or off testing of compression of the output of the CGI program which is being tested. Give any true value as the first argument to turn on compression testing. Give any false value to turn off compression testing. Tests are done via Gzip::Faster.

Prior to version 0.07 of this module, these tests were done by IO::Uncompress::Gunzip.

expect_charset

$tester->expect_charset ('UTF-8');

Tell the tester to test whether the header declares the output character set correctly.

If you set expect charset, then the body of the output is upgraded from that encoding into Perl's Unicode encoding, utf8. Unless the encoding is UTF-8, that upgrading is also added as a pass or fail test:

$tester->expect_charset ('EUC-JP');

adds a test for decoding from the EUC-JP encoding.

This behaviour is new in version 0.08 of this module. Prior to version 0.08, $output{body} was not upgraded to utf8.

new

my $tester = Test::CGI::External->new ();

Create a new testing object.

plan

Print the TAP (Test Anything Protocol) plan. This has to be done at the end of the execution. You usually don't have to print this but can use "done_testing" from Test::More since this module uses Test::Builder internally.

run

my %options;
$options{QUERY_STRING} = "q=rupert+the+bear";
$tester->run (\%options);

Run the cgi executable specified using "set_cgi_executable" with the inputs specified in %options. See "Possible options" for possible options. See "Outputs" for outputs.

set_cgi_executable

$tester->set_cgi_executable ('my.cgi');

Set the CGI program to be tested to my.cgi. This checks whether the file exists and is executable, and prints a warning if either of these checks fails. It's also possible to send command-line options to the program. Things after the name of the executable are sent as command-line options to the CGI program.

$tester->set_cgi_executable ('my.cgi', '-o', 'xyz');

set_verbosity

$tester->set_verbosity (1);

This turns on or off messages from the module informing you of what it is doing.

set_no_check_content

$tester->set_no_check_content (1);

This turns off testing of the "Content-Type" HTTP header. For example if you want to send redirects or "not modified" responses, you usually will not send any content, but just the HTTP headers, so you don't need a "Content-Type" header.

INPUT AND OUTPUT

Possible options

The following values may be set in the argument to "run", %options.

CONTENT_TYPE
$options{CONTENT_TYPE} = 'GET';
$test->run (\%options);

The content type of the input. This is used when REQUEST_METHOD is POST. It is usually either application/x-www-form-urlencoded or multipart/form-data. application/x-www-form-urlencoded is the default value for CGI form queries.

die_on_failure
$options{die_on_failure} = 1;
$test->run (\%options);

If this is set to a true value, the module "dies" if any test fails. If this is set to a false value then the program does not die, regardless of whether tests fail or not.

expect_errors
$options{expect_errors} = 1;
$test->run (\%options);

Set to a true value if the program is expected to produce errors. In other words, this switches off the test that errors are not printed.

html
$options{html} = 1;
$test->run (\%options);

If set to a true value, validate the html using projects/html-validate/validate.go. See "BUGS".

$options{HTTP_COOKIE} = 'nice=day';
$test->run (\%options);

This option sets the environment variable HTTP_COOKIE to whatever its value is. The environment variable is then unset at the end of the test run.

input
$options{input} = $post_input;
$test->run (\%options);

Input to send to the CGI program with a POST request. The environment variable CONTENT_LENGTH in the CGI program is automatically set to the length of this variable. See also "BUGS".

json
$options{json} = 1;
$test->run (\%options);

Validate the body of the output as JSON using JSON::Parse. This is run after decompression.

no_check_content
$options{no_check_content} = 1;
$test->run (\%options);

If this is set to a true value, the program does not check for the "Content-Type" header line produced by the CGI. This option is for the case where the CGI produces, for example, a "Location: " response without a body. See also the "set_no_check_content" method.

QUERY_STRING
$options{QUERY_STRING} = "word=babies";
$test->run (\%options);

This option sets the environment variable QUERY_STRING to whatever its value is. The environment variable is then unset at the end of the test run.

REMOTE_ADDR
$options{QUERY_STRING} = "127.0.0.1";
$test->run (\%options);

This option sets the environment variable REMOTE_ADDR to whatever its value is. The environment variable is then unset at the end of the test run.

REQUEST_METHOD
$options{REQUEST_METHOD} = "GET";
$test->run (\%options);

This option may be set to one of POST, GET and HEAD. The module then sets the environment variable REQUEST_METHOD to this value. If not set at all, the module sets it to a default and prints a warning message. You can also set this to any other value you want, like OPTIONS or something, but the module prints a warning message. There is currently no way to switch off the warnings. See also "BUGS".

Outputs

The various outputs of the CGI program are also put into %options.

body
my %options;
$test->run (\%options);
my $body = $options{body};

The body of the CGI output, the part after the headers. If you have requested compression testing with "do_compression_test", this will be the output after uncompression.

This should be upgraded into Unicode using the character encoding specified with "expect_charset", but it isn't at the moment. See also "BUGS".

content_length

The content length of your input in bytes, if you are making a POST request. Note that this is the length in bytes, so it may differ from the return value of Perl's length function.

use utf8;
use FindBin '$Bin';
use Test::More;
my $stuff = 'ばびぶべぼ';
note (length ($stuff));
use Test::CGI::External;
my %options;
$options{input} = $stuff;
my $tester = Test::CGI::External->new ();
$tester->set_cgi_executable ("$Bin/../t/test.cgi");
$tester->run (\%options);
note ($options{content_length});
$tester->plan ();
error_output
my %options;
$test->run (\%options);
my $error_output = $options{error_output};

Any errors output by the CGI program. This is an empty string if there were no errors. If you are expecting to get error messages, remember to set "expect_errors", otherwise any error output at all will cause a test to fail.

exit_code
$test->run (\%options);
my $exit_code = $options{exit_code};

The exit value of the CGI program, the value of $status in

$status = system ('example.cgi');
$test->run (\%options);
my $header = $options{header};

The header part of the CGI output. This is split from "output".

headers
$test->run (\%options);
my $headers = $options{headers};
print $headers->{'content-type'};

The received headers, parsed and put into lower case, with the key/value pairs of the hash reference $headers the keys and values from the HTTP header.

output
$test->run (\%options);
my $output = $options{output};

The entire output of the CGI program, unprocessed. If you have requested compression testing with "do_compression_test", this will contain binary compressed data.

BUGS

This assumes line endings are \n in some places. There may be problems with \r\n support.

The html validator mentioned above is a private program. This module was removed from CPAN and this was added when the whole module was "privatized".

The tests use the internals of Test::Builder, and the pass/fail test messages are somewhat disorganized.

The test contents are not documented.

The mixture of methods (see "METHODS") and options (see "Possible options") is somewhat messy.

There are too many warnings which cannot be switched off, e.g. the request method warnings.

The examples in this documentation are not machine-readable, and thus probably contain many errors. (JSON::Create is an example of a module with documentation I think is good, because it's all extracted from actual example programs, which are test-run during the build.)

The module has very few tests.

No check for MD5 checksums. For completeness, there probably should be a check for this.

Not adapted for Microsoft Windows.

CONTENT_LENGTH is set from length ($input), so it may be broken for utf8 strings.

SEE ALSO

Specification of the Common Gateway Interface

The current specification of the Common Gateway Interface is RFC (Request For Comments) 3875 by D. Robinson and K. Coar of The Apache Software Foundation, dated October 2004. See http://www.ietf.org/rfc/rfc3875.

Specification for HTTP headers

This module's check for HTTP headers was written against the specification on pages 15 and 16 of RFC 2616 by R. Fielding et al, dated June 1999. See http://www.ietf.org/rfc/rfc2616.txt.

The Common Gateway Interface

This is my own web page which explains some things about CGI. (The strange design is because I used this as a test page for responsive web design class.)

DEPENDENCIES

This module depends on

Carp

Carp is used to print error messages.

Encode

Encode is used for converting non-UTF-8 encodings into Unicode.

Gzip::Faster

It is used to do the compression testing.

File::Temp

File::Temp is used for the temporary files which store the input, output, and error stream of the CGI program.

HTTP::Date

HTTP::Date is used to check the dates, if you check caching.

JSON::Parse

JSON::Parse is used to test JSON for validity.

Test::Builder

For testing framework.

Unicode::UTF8

Unicode::UTF8 is used for converting UTF-8 encodings into Perl's internal Unicode.

The module also used to depend on IPC::Run3, but there were some issues with this module messing around with the global variables. It does something like binmode STDOUT, which interferes with other parts of the program, so that had to be removed.

AUTHOR

Ben Bullock, <bkb@cpan.org>

Request

If you'd like to see this module continued, let me know that you're using it. For example, send an email, write a bug report, star the project's github repository, add a patch, add a ++ on Metacpan.org, or write a rating at CPAN ratings. It really does make a difference. Thanks.

COPYRIGHT & LICENCE

This package and associated files are copyright (C) 2011-2015 Ben Bullock.

You can use, copy, modify and redistribute this package and associated files under the Perl Artistic Licence or the GNU General Public Licence.

TERMINOLOGY

This defines the terminology used in this document.

Convenience function

In this document, a "convenience function" indicates a function which solves some of the problems, some of the time, for some of the people, but which may not be good enough for all envisaged uses. A convenience function is an 80/20 solution, something which solves (about) 80% of the problems with 20% of the effort. Something which does the obvious things, but may not do all the things you might want, a time-saver for the most basic usage cases.

BUGS

In this document, the section BUGS describes possible deficiencies, problems, and workarounds with the module. It's not a guide to bug reporting, or even a list of actual bugs. The name "BUGS" is the traditional name for this sort of section in a Unix manual page.