Sign In/My Account | View Cart  
advertisement


Listen Print

Testing mod_perl 2.0
by Geoffrey Young | Pages: 1, 2, 3

More and More Tests

What other aspects of the filter can we put to the test? If you recall from our discussion of output filters last time, one of the responsibilities of filters that alter content is to remove the generated Content-Length header from the server response. The relevant code for this in our filter was as follows.

  
# output filters that alter content are responsible for removing
# the Content-Length header, but we only need to do this once.
$r->headers_out->unset('Content-Length');
  

Here is the test for this bit of logic, which checks that the Content-Length header is indeed present for plain documents, but removed by our filter for HTML documents. Again, we will be using the existing /level URI to request both index.txt and index.html.

  
use Apache::Test;
use Apache::TestRequest;

plan tests => 2, have_lwp;

my $response = GET '/level/index.txt';
ok ($response->content_length == 58);

$response = GET '/level/index.html';
ok (! $response->content_length);
  

Note the use of the content_length() method on our HTTP::Response object to retrieve the Content-Length of the server response. Remember that you have all the methods from that class to choose from in your tests.

The final test we will take a look at is the example we used previous time to illustrate our filter does indeed co-exist with both mod_include and mod_cgi. As it turns out, the example was taken right from the test suite (always a good place from which to draw examples). Here is the extra.conf.in snippet.

  
Alias /cgi-bin @ServerRoot@/cgi-bin
<Location /cgi-bin>
  SetHandler cgi-script

  SetOutputFilter INCLUDES
  PerlOutputFilterHandler Apache::Clean

  PerlSetVar CleanOption shortertags
  PerlAddVar CleanOption whitespace
  Options +ExecCGI +Includes
</Location>
  

The nature of our test requires that both mod_include and a suitable CGI platform (either mod_cgi or mod_cgid) be available to Apache - without both of these, our tests are doomed to failure, so we need a way to test whether these modules are available to the server before planning the individual tests. Also required are some CGI scripts, the location of which is specified by expanding @ServerRoot@. To include these scripts, we could just create a t/cgi-bin/ directory and place the relevant files in it. However, any CGI scripts we create would probably include a platform-specific shebang line like #!/usr/bin/perl. A better solution is to generate the scripts on-the-fly, specifying a shebang line that matches the version of Perl we are using to build and test the module.

Despite the extra work required, the test script used for this test is only a bit more complex than others we have seen so far.

  
use Apache::Test;
use Apache::TestRequest;
use Apache::TestUtil qw(t_write_perl_script);

use File::Spec::Functions qw(catfile);

plan tests => 4, (have_lwp && 
                  have_cgi &&
                  have_module('include'));

my @lines = <DATA>;
t_write_perl_script(catfile(qw(cgi-bin plain.cgi)), @lines[0,2]);
t_write_perl_script(catfile(qw(cgi-bin include.cgi)), @lines[1,2]);

my $response = GET '/cgi-bin/plain.cgi';
chomp(my $content = $response->content);

ok ($content eq q!<strong>/cgi-bin/plain.cgi</strong>!);
ok ($response->content_type =~ m!text/plain!);

$response = GET '/cgi-bin/include.cgi';
chomp($content = $response->content);

ok ($content eq q!<b>/cgi-bin/include.cgi</b>!);
ok ($response->content_type =~ m!text/html!);

__END__
print "Content-Type: text/plain\n\n";
print "Content-Type: text/html\n\n";
print '<strong><!--#echo var="DOCUMENT_URI" --></strong>';
  

The first thing to note is that we have joined the familiar call to have_lwp() with additional calls to have_cgi() and have_module(). The Apache::Test package comes with a number of handy shortcuts for querying the server for information. have_cgi() returns true if either mod_cgi or mod_cgid are installed. have_module() is more generic and can be used to test for either Apache C modules or Perl modules - for instance, have_module('Template') could be used to check whether the Template Toolkit is installed.

For generation of the CGI scripts, we use the t_write_perl_script() function from the Apache::TestUtil package. t_write_perl_script() takes two arguments, the first of which is the name of the file to generate, relative to the t/ directory in the distribution. If the file includes a path, any necessary directories are automatically created. In the interests of portability, we use catfile() from the File::Spec::Functions package to join the file with the directory. In general, you will want to keep File::Spec and its associated classes in mind when writing your tests - you never know when somebody is going to try and run them on Win32 or VMS. The second argument to t_write_perl_script() is a list of lines to append to the file after the (calculated) shebang line.

Although t_write_perl_script() cleans up any generated files and directories when the test completes, if we were to intercept include.cgi before removal it would look similar to something we would have written ourselves.

  
#!/src/bleedperl/bin/perl
# WARNING: this file is generated, do not edit
# 01: /src/bleedperl/lib/site_perl/5.9.0/i686-linux-thread-multi/
      Apache/TestUtil.pm:129
# 02: 06mod_cgi.t:18
print "Content-Type: text/html\n\n";
print '<strong><!--#echo var="DOCUMENT_URI" --></strong>';
  

As you probably have guessed by now, just as we ran tests against scripts in the (generated) t/cgi-bin/ directory, we can add other directories to t/ for other kinds of tests. For instance, we can create t/perl-bin/ to hold standard ModPerl::Registry scripts (remember, you don't need to generate a shebang line for those). We can even create t/My/ to hold a custom My::ContentGenerator handler, which can be used just like any other Perl module during Apache's runtime. All in all, you can simulate practically any production environment imaginable.

But Wait, There's More!

The tests presented here should be enough to get you started writing tests for your own modules, but they are only part of the story. If you are interested in seeing some of the other tests written to support this article, the Apache::Clean distribution is full of all kinds of different tests and test approaches, including some that integrate custom handlers as well as one that tests the POD syntax for the module. In fact, you will find 26 different tests in 12 test files there, free for the taking.

Stuck using mod_perl 1.0? One of the best things about Apache-Test is that it is flexible and intelligent enough to be used for mod_perl 1.0 handlers as well. In fact, the recent release of Apache-Test as a CPAN module outside of the mod_perl 2.0 distribution makes it even easier for all mod_perl developers to take advantage of the framework. For the most part, the instructions in this article should be enough to get you going writing tests for 1.0-based modules - the only changes specific to 1.0 modules rest in the Makefile.PL. I took the time to whip up a version of Apache::Clean for mod_perl 1.0 that parallels the functionality in these articles, which you can find next to the 2.0 version. The 1.0 distribution runs against the exact same *.t files (where applicable) and includes a sample 1.0 Makefile.PL.

Personally, I don't know how I ever got along without Apache-Test, and I'm sure that once you start using it you will feel the same. Secretly, I'm hoping that Apache-Test becomes so popular that end-users start wrapping their bug reports up in little, self-contained, Apache-Test-based tarballs so anyone can reproduce the problem.

More Information

This article was derived from Recipe 7.7 in the mod_perl Developer's Cookbook, adjusted to accommodate both mod_perl 2.0 and changes in the overall Apache-Test interface that have happened since publication. Despite these differences, the recipe is useful for its additional descriptions and coverage of features not discussed here. You can read Recipe 7.7, as well as the rest of Chapter 7 from the book's website. Also, in addition to the Apache-Test manpage and README there is also the Apache-Test tutorial on the mod_perl Project website, all of which are valuable sources of information.

Thanks

The Apache-Test project is the result of the tireless efforts of many, many developers - far too many to name individually here. However, there has has been a recent surge of activity as Apache-Test made its way to CPAN, especially in making it more platform aware and solving a few back compatibility problems with the old Apache::test that ships with mod_perl 1.0. Special thanks are due to Stas Bekman, David Wheeler, and Randy Kobes for helping to polish Apache-Test on Win32 and Mac OS X without requiring major changes to the API.