| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| package Apache::TestMB; |
| |
| use strict; |
| use vars qw(@ISA); |
| use Module::Build 0.18; |
| use Apache::Test (); |
| use Apache::TestConfig (); |
| @ISA = qw(Module::Build); |
| |
| sub new { |
| my $pkg = shift; |
| my($argv, $vars) = |
| Apache::TestConfig::filter_args(\@ARGV, \%Apache::TestConfig::Usage); |
| @ARGV = @$argv; |
| my $self = $pkg->SUPER::new(@_); |
| $self->{properties}{apache_test_args} = $vars; |
| $self->{properties}{apache_test_script} ||= 't/TEST'; |
| $self->generate_script; |
| return $self; |
| } |
| |
| sub valid_property { |
| return 1 if defined $_[1] && |
| ($_[1] eq 'apache_test_args' || $_[1] eq 'apache_test_script'); |
| shift->SUPER::valid_property(@_); |
| } |
| |
| sub apache_test_args { |
| my $self = shift; |
| $self->{properties}{apache_test_args} = shift if @_; |
| return $self->{properties}{apache_test_args}; |
| } |
| |
| sub apache_test_script { |
| my $self = shift; |
| $self->{properties}{apache_test_script} = shift if @_; |
| return $self->{properties}{apache_test_script}; |
| } |
| |
| sub ACTION_test_clean { |
| my $self = shift; |
| # XXX I'd love to do this without t/TEST. |
| $self->do_system( $self->perl, $self->_bliblib, |
| $self->localize_file_path($self->apache_test_script), |
| '-clean'); |
| } |
| |
| sub ACTION_clean { |
| my $self = shift; |
| $self->depends_on('test_clean'); |
| $self->SUPER::ACTION_clean(@_); |
| } |
| |
| sub ACTION_run_tests { |
| my $self = shift; |
| $self->depends_on('test_clean'); |
| # XXX I'd love to do this without t/TEST. |
| $self->do_system($self->perl, $self->_bliblib, |
| $self->localize_file_path($self->apache_test_script), |
| '-bugreport', '-verbose=' . ($self->verbose || 0)); |
| } |
| |
| sub ACTION_testcover { |
| my $self = shift; |
| |
| unless ($self->find_module_by_name('Devel::Cover', \@INC)) { |
| warn("Cannot run testcover action unless Devel::Cover " |
| . "is installed.\n" . |
| "Don't forget to rebuild your Makefile after " |
| . "installing Devel::Cover\n"); |
| return; |
| } |
| |
| $self->add_to_cleanup('coverage', 'cover_db'); |
| |
| my $atdir = $self->localize_file_path("$ENV{HOME}/.apache-test"); |
| local $Test::Harness::switches = |
| local $Test::Harness::Switches = |
| local $ENV{HARNESS_PERL_SWITCHES} = "-MDevel::Cover=+inc,'$atdir'"; |
| local $ENV{APACHE_TEST_EXTRA_ARGS} = "-one-process"; |
| |
| $self->depends_on('test'); |
| $self->do_system('cover'); |
| } |
| |
| sub ACTION_test_config { |
| my $self = shift; |
| $self->do_system($self->perl, $self->_bliblib, |
| $self->localize_file_path($self->apache_test_script), |
| '-conf', '-verbose=' . ($self->verbose || 0)); |
| } |
| |
| sub _bliblib { |
| my $self = shift; |
| return ( |
| '-I', File::Spec->catdir($self->base_dir, $self->blib, 'lib'), |
| '-I', File::Spec->catdir($self->base_dir, $self->blib, 'arch'), |
| ); |
| } |
| |
| sub ACTION_test { |
| my $self = shift; |
| $self->depends_on('code'); |
| $self->depends_on('run_tests'); |
| $self->depends_on('test_clean'); |
| } |
| |
| sub _cmodules { |
| my ($self, $action) = @_; |
| die "The cmodules" . ( $action ne 'all' ? "_$action" : '') |
| . " action is not yet implemented"; |
| # XXX TBD. |
| $self->depends_on('test_config'); |
| my $start_dir = $self->cwd; |
| chdir $self->localize_file_path('c-modules'); |
| # XXX How do we get Build.PL to be generated instead of Makefile? |
| # Subclass Apache::TestConfigC, perhaps? |
| $self->do_system('Build.PL', $action); |
| chdir $start_dir; |
| } |
| |
| sub ACTION_cmodules { shift->_cmodues('all') } |
| sub ACTION_cmodules_clean { shift->_cmodues('clean') } |
| |
| # XXX I'd love to make this optional. |
| sub generate_script { |
| my $self = shift; |
| |
| # If a file name has been passed in, use it. Otherwise, use the |
| # one set up when the Apache::TestMB object was created. |
| my $script = $self->localize_file_path($_[0] |
| ? $self->apache_test_script(shift) |
| : $self->apache_test_script |
| ); |
| |
| # We need a class to run the tests from t/TEST. |
| my $class = pop || 'Apache::TestRunPerl'; |
| |
| # Delete any existing instance of the file. |
| unlink $script if -e $script; |
| |
| # Start the contents of t/TEST. |
| my $body = "BEGIN { eval { require blib && blib->import; } }\n"; |
| |
| # Configure the arguments for t/TEST. |
| while (my($k, $v) = each %{ $self->apache_test_args }) { |
| $v =~ s/\|/\\|/g; |
| $body .= "\n\$Apache::TestConfig::Argv{'$k'} = q|$v|;\n"; |
| } |
| |
| my $infile = "$script.PL"; |
| if (-f $infile) { |
| # Use the existing t/TEST.PL. |
| my $in = Symbol::gensym(); |
| open $in, "$infile" or die "Couldn't open $infile: $!"; |
| local $/; |
| $body .= <$in>; |
| close $in; |
| } else { |
| # Create t/TEST from scratch. |
| $body .= join "\n", |
| Apache::TestConfig->perlscript_header, |
| "use $class ();", |
| "$class->new->run(\@ARGV);"; |
| } |
| |
| # Make it so! |
| print "Generating test running script $script\n" if $self->verbose; |
| Apache::Test::basic_config()->write_perlscript($script, $body); |
| $self->add_to_cleanup($self->apache_test_script); |
| } |
| |
| |
| 1; |
| __END__ |
| |
| =head1 NAME |
| |
| Apache::TestMB - Subclass of Module::Build to support Apache::Test |
| |
| =head1 SYNOPSIS |
| |
| Standard process for building & installing modules: |
| |
| perl Build.PL |
| ./Build |
| ./Build test |
| ./Build install |
| |
| Or, if you're on a platform (like DOS or Windows) that doesn't like the "./" |
| notation, you can do this: |
| |
| perl Build.PL |
| perl Build |
| perl Build test |
| perl Build install |
| |
| =head1 DESCRIPTION |
| |
| This class subclasses C<Module::Build> to add support for testing |
| Apache integration with Apache::Test. It is broadly based on |
| C<Apache::TestMM>, and as such adds a number of build actions to a the |
| F<Build> script, while simplifying the process of creating F<Build.PL> |
| scripts. |
| |
| Here's how to use C<Apache::TestMB> in a F<Build.PL> script: |
| |
| use Module::Build; |
| |
| my $build_pkg = eval { require Apache::TestMB } |
| ? 'Apache::TestMB' : 'Module::Build'; |
| |
| my $build = $build_pkg->new( |
| module_name => 'My::Module', |
| ); |
| $build->create_build_script; |
| |
| This is identical to how C<Module::Build> is used. Not all target |
| systems may have C<Apache::Test> (and therefore C<Apache::TestMB> |
| installed, so we test for it to be installed, first. But otherwise, |
| its use can be exactly the same. Consult the |
| L<Module::Build|Module::Build> documentation for more information on |
| how to use it; L<Module::Build::Cookbook|Module::Build::Cookbook> may |
| be especially useful for those looking to migrate from |
| C<ExtUtils::MakeMaker>. |
| |
| =head1 INTERFACE |
| |
| =head2 Build |
| |
| With the above script, users can build your module in the usual |
| C<Module::Build> way: |
| |
| perl Build.PL |
| ./Build |
| ./Build test |
| ./Build install |
| |
| If C<Apache::TestMB> is installed, then Apache will be started before |
| tests are run by the C<test> action, and shut down when the tests |
| complete. Note that C<Build.PL> can be called C<Apache::Test>-specific |
| options in addition to the usual C<Module::Build> options. For |
| example: |
| |
| perl Build.PL -apxs /usr/local/apache/bin/apxs |
| |
| Consult the L<Apache::Test|Apache::Test> documentation for a complete |
| list of options. |
| |
| In addition to the actions provided by C<Module::Build> (C<build>, |
| C<clean>, C<code>, C<test>, etc.), C<Apache::TestMB> adds a few extra |
| actions: |
| |
| =over 4 |
| |
| =item test_clean |
| |
| This action cleans out the files generated by the test script, |
| F<t/TEST>. It is also executed by the C<clean> action. |
| |
| =item run_tests |
| |
| This action actually the tests by executing the test script, |
| F<t/TEST>. It is executed by the C<test> action, so most of the time |
| it won't be executed directly. |
| |
| =item testcover |
| |
| C<Apache::TestMB> overrides this action from C<Module::Build> in order to |
| prevent the C<Apache::Test> preference files from being included in the test |
| coverage. |
| |
| =back |
| |
| =head2 Constructor |
| |
| =head3 new |
| |
| The C<new()> constructor takes all the same arguments as its parent in |
| C<Module::Build>, but can optionally accept one other parameter: |
| |
| =over |
| |
| =item apache_test_script |
| |
| The name of the C<Apache::Test> test script. The default value is |
| F<t/TEST>, which will work in the vast majority of cases. If you wish |
| to specify your own file name, do so with a relative file name using |
| Unix-style paths; the file name will automatically be converted for |
| the local platform. |
| |
| =back |
| |
| When C<new()> is called it does the following: |
| |
| =over 4 |
| |
| =item * |
| |
| Processes the C<Apache::Test>-specific options in C<@ARGV>. See the |
| L<Apache::Test|Apache::Test> documentation for a complete list of |
| options. |
| |
| =item * |
| |
| Sets the name of the C<Apache::Test> test script to F<t/TEST>, unless |
| it was explicitly specified by the C<apache_test_script> parameter. |
| |
| =item * |
| |
| Calls C<generate_script()> to generate C<Apache::Test> test script, |
| usually F<t/TEST>. |
| |
| =back |
| |
| =head2 Instance Methods |
| |
| =head3 apache_test_args |
| |
| Returns a hash reference containing all of the settings specified by |
| options passed to F<Build.PL>, or explicitly added to C<@ARGV> in |
| F<Build.PL>. Consult the L<Apache::Test|Apache::Test> documentation |
| for a complete list of options. |
| |
| =head3 apache_test_script |
| |
| Gets or sets the file name of the C<Apache::Test> test script. |
| |
| =head3 generate_script |
| |
| $build->generate_script; |
| $build->generate_script('t/FOO'); |
| $build->generate_script(undef, 'Apache::TestRun'); |
| |
| This method is called by C<new()>, so in most cases it can be |
| ignored. If you'd like it to use other than the default arguments, you |
| can call it explicitly in F<Build.PL> and pass it the arguments you |
| desire. It takes two optional arguments: |
| |
| =over 4 |
| |
| =item * |
| |
| The name of the C<Apache::Test> test script. Defaults to the value |
| returned by C<apache_test_script()>. |
| |
| =item * |
| |
| The name of an C<Apache::Test> test running class. Defaults to |
| C<Apache::TestRunPerl>. |
| |
| =back |
| |
| If there is an existing F<t/TEST.PL> (or a script with the same name |
| as specified by the C<apache_test_script> parameter but with F<.PL> |
| appended to it), then that script will be used as the template for the |
| test script. Otherwise, a simple test script will be written similar |
| to what would be written by C<Apache::TestRun::generate_script()> |
| (although that function is not aware of the arguments passed to |
| F<Build.PL>, so use this one instead!). |
| |
| =head1 SEE ALSO |
| |
| =over 4 |
| |
| =item L<Apache::TestRequest|Apache::TestRequest> |
| |
| Demonstrates how to write tests to send requests to the Apache server |
| run by C<./Build test>. |
| |
| =item L<Module::Build|Module::Build> |
| |
| The parent class for C<Apache::TestMB>; consult it's documentation for |
| more on its interface. |
| |
| =item L<http://www.perl.com/pub/a/2003/05/22/testing.html> |
| |
| This article by Geoffrey Young explains how to configure Apache and |
| write tests for your module using Apache::Test. Just use |
| C<Apache::TestMB> instead of C<Apache::TestMM> to update it for use |
| with C<Module::Build>. |
| |
| =back |
| |
| =head1 AUTHOR |
| |
| David Wheeler |
| |
| Questions can be asked at the test-dev <at> httpd.apache.org list. For |
| more information see: I<http://httpd.apache.org/test/> and |
| I<http://perl.apache.org/docs/general/testing/testing.html>. |
| |
| =cut |
| |