dougm       00/09/28 14:16:15

  Modified:    .        Changes ToDo
               lib/Apache test.pm
  Log:
  Apache::test enhancements
  
  Revision  Changes    Path
  1.539     +3 -0      modperl/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl/Changes,v
  retrieving revision 1.538
  retrieving revision 1.539
  diff -u -r1.538 -r1.539
  --- Changes   2000/09/28 21:00:43     1.538
  +++ Changes   2000/09/28 21:16:07     1.539
  @@ -10,6 +10,9 @@
   
   =item 1.24_01-dev
   
  +Apache::test enhancements
  +[Ken Williams <[EMAIL PROTECTED]>]
  +
   fix Apache::exit() so it does it does not trigger a warning (maybe)
   
   change Apache::PerlRun's Apache class relationship from is-a to has-a
  
  
  
  1.262     +0 -2      modperl/ToDo
  
  Index: ToDo
  ===================================================================
  RCS file: /home/cvs/modperl/ToDo,v
  retrieving revision 1.261
  retrieving revision 1.262
  diff -u -r1.261 -r1.262
  --- ToDo      2000/09/28 19:59:25     1.261
  +++ ToDo      2000/09/28 21:16:07     1.262
  @@ -40,8 +40,6 @@
   
   - replace Apache::StatINC with Apache::ModuleReload?
   
  -- ken w's Apache::test patch
  -
   - CHECK blocks? [Michael J Schout <[EMAIL PROTECTED]>]
   
   - see if possible to have the dso libperl.so be named something else,
  
  
  
  1.17      +304 -17   modperl/lib/Apache/test.pm
  
  Index: test.pm
  ===================================================================
  RCS file: /home/cvs/modperl/lib/Apache/test.pm,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- test.pm   2000/03/06 20:38:22     1.16
  +++ test.pm   2000/09/28 21:16:13     1.17
  @@ -44,6 +44,156 @@
       *Apache::Constants::bootstrap = sub {};
   }
   
  +sub write_httpd_conf {
  +    my $pkg = shift;
  +    my %args = (conf_file => 't/httpd.conf', @_);
  +    my $DIR = `pwd`; chomp $DIR;
  +
  +    local *CONF;
  +    open CONF, ">$args{conf_file}" or die "Can't create $args{conf_file}: $!";
  +    print CONF <<EOF;
  +
  +Port $args{port}
  +User $args{user}
  +Group $args{group}
  +ServerName localhost
  +DocumentRoot $DIR/t/eg
  +
  +$args{modules}
  +
  +ErrorLog $DIR/t/error_log
  +PidFile $DIR/t/httpd.pid
  +AccessConfig /dev/null
  +ResourceConfig /dev/null
  +LockFile $DIR/t/httpd.lock
  +TypesConfig /dev/null
  +TransferLog /dev/null
  +ScoreBoardFile /dev/null
  +
  +AddType text/html .html
  +
  +# Look in ./blib/lib
  +PerlModule ExtUtils::testlib
  +
  +$args{include}
  +EOF
  +
  +    return 1;
  +}
  +
  +sub _ask {
  +    my ($prompt, $default, $mustfind) = @_;
  +
  +    my $response;
  +    do {
  +     print "$prompt [$default]: ";
  +     chomp($response = <STDIN>);
  +     $response ||= $default;
  +    } until (!$mustfind || (-e $response || !print("$response not found\n")));
  +
  +    return $response;
  +}
  +
  +sub get_test_params {
  +    my $pkg = shift;
  +
  +    print("\nFor testing purposes, please give the full path to an httpd\n",
  +       "with mod_perl enabled.  The path defaults to \$ENV{APACHE}, if present.");
  +    
  +    my %conf;
  +    
  +    my $httpd = $ENV{'APACHE'} || which('apache') || which('httpd') || 
'/usr/lib/httpd/httpd';
  +
  +    $httpd = _ask("\n", $httpd, 1);
  +    system "$Config{lns} $httpd t/httpd";
  +
  +    if (lc _ask("Search existing config file for dynamic module dependencies?", 
'n') eq 'y') {
  +     my %compiled;
  +     for (`t/httpd -V`) {
  +         if (/([\w]+)="(.*)"/) {
  +             $compiled{$1} = $2;
  +         }
  +     }
  +     $compiled{SERVER_CONFIG_FILE} =~ s,^,$compiled{HTTPD_ROOT}/,
  +         unless $compiled{SERVER_CONFIG_FILE} =~ m,^/,;
  +     
  +     my $file = _ask("  Config file", $compiled{SERVER_CONFIG_FILE}, 1);
  +     $conf{modules} = $pkg->_read_existing_conf($file);
  +    }
  +
  +    # Get default user (apache doesn't like to run as root, special-case it)
  +    my $defuser = ($< && getpwuid $<) || 'nobody';
  +    $conf{user} = _ask("User to run tests under", $defuser);
  +
  +    my $defgroup = ($defuser eq 'nobody' ? 'nobody' : getgrgid((getpwnam 
$conf{user})[3]));
  +    $conf{group} = _ask("Group to run tests under", $defgroup);
  +
  +    $conf{port} = _ask("Port to run tests under", 8228);
  +
  +    return %conf;
  +}
  +
  +sub _read_existing_conf {
  +    # Returns some config text 
  +    shift;
  +    my ($server_conf) = @_;
  +    
  +    
  +    open SERVER_CONF, $server_conf or die "Couldn't open $server_conf: $!";
  +    my @lines = grep {!m/^\s*#/} <SERVER_CONF>;
  +    close SERVER_CONF;
  +    
  +    my @modules       =   grep /^\s*(Add|Load)Module/, @lines;
  +    my ($server_root) = (map /^\s*ServerRoot\s*(\S+)/, @lines);
  +
  +    # Rewrite all modules to load from an absolute path.
  +    foreach (@modules) {
  +     s!(\s)([^/\s]\S+/)!$1$server_root/$2!;
  +    }
  +    
  +    # Directories where apache DSOs live.
  +    my (@module_dirs) = map {m,(/\S*/),} @modules;
  +    
  +    # Have to make sure that dir, autoindex and perl are loaded.
  +    my @required  = qw(dir autoindex perl);
  +    
  +    my @l = `t/httpd -l`;
  +    my @compiled_in = map /^\s*(\S+)/, @l[1..@l-2];
  +    
  +    my @load;
  +    foreach my $module (@required) {
  +     if (!grep /$module/i, @compiled_in, @modules) {
  +         push @load, $module;
  +     }
  +    }
  +    
  +    # Finally compute the directives to load modules that need to be loaded.
  + MODULE:
  +    foreach my $module (@load) {
  +     foreach my $module_dir (@module_dirs) {
  +         if (-e "$module_dir/mod_$module.so") {
  +             push @modules, "LoadModule ${module}_module 
$module_dir/mod_$module.so\n"; next MODULE;
  +         } elsif (-e "$module_dir/lib$module.so") {
  +             push @modules, "LoadModule ${module}_module 
$module_dir/lib$module.so\n"; next MODULE;
  +         } elsif (-e "$module_dir/ApacheModule\u$module.dll") {
  +             push @modules, "LoadModule ${module}_module 
$module_dir/ApacheModule\u$module.dll\n"; next MODULE;
  +         }
  +     }
  +    }
  +                   
  +    print "found the following modules: \n@modules";
  +    return join '', @modules;
  +}
  +
  +# Find an executable in the PATH.
  +sub which {
  +    foreach (map { "$_/$_[0]" } split /:/, $ENV{PATH}) {
  +     next unless m,^/,;
  +     return $_ if -x;
  +    }
  +}
  +
  +
   sub test { 
       my $s = $_[1] ? "ok $_[0]\n" : "not ok $_[0]\n";
       if($ENV{MOD_PERL}) {
  @@ -190,34 +340,42 @@
   }
   
   sub MM_test {
  -    my $script = "t/TEST";
  -    my $my_test = q(
  +    shift();  # Don't need package name
  +    my %conf = @_;
  +
  +    my $section = <<EOF;
  +TEST_VERBOSE=0
  +TEST_TYPE=test_\$(LINKTYPE)
  +TEST_FILE = test.pl
  +TEST_FILES = t/*.t
  +TESTDB_SW = -d
   
  -test:        run_tests
  +#test:       start_httpd run_tests   kill_httpd
   
  -);
  +test :: pure_all start_httpd run_tests   kill_httpd
   
  -    join '', qq(
  -MP_TEST_SCRIPT=$script
  -),
  -    q(
  -TEST_VERBOSE=0
  +testdb:      start_httpd run_testsdb kill_httpd
   
   kill_httpd:
  -     kill `cat t/logs/httpd.pid`
  +     kill `cat t/httpd.pid`
   
  -start_httpd: 
  -     ./httpd -X -d `pwd`/t &
  +start_httpd:
  +     t/httpd -f `pwd`/t/httpd.conf
   
  -rehttpd:   kill_httpd start_httpd
  +run_tests :: pure_all
  +     PERL_DL_NONLAZY=1 PORT=$conf{port}
  +EOF
  +    chomp $section;
   
  -run_tests:
  -     $(FULLPERL) $(MP_TEST_SCRIPT) $(TEST_VERBOSE)
  +    $section .= <<'EOF';
  + $(FULLPERL) -I$(INST_ARCHLIB) -I$(INST_LIB) -I$(PERL_ARCHLIB) -I$(PERL_LIB) -e 
'use Test::Harness qw(&runtests $$verbose); $$verbose=$(TEST_VERBOSE); runtests 
@ARGV;' $(TEST_FILES)
   
  -),
  +run_testsdb :: pure_all
  +     PERL_DL_NONLAZY=1 $(FULLPERL) $(TESTDB_SW) -I$(INST_ARCHLIB) -I$(INST_LIB) 
-I$(PERL_ARCHLIB) -I$(PERL_LIB) $(TEST_FILE)
   
  -$my_test;
  +EOF
   
  +    return $section;
   }
   
   sub grab {
  @@ -326,3 +484,132 @@
   1;
   
   __END__
  +
  +=head1 NAME
  +
  +Apache::Test - Facilitates testing of Apache::* modules
  +
  +=head1 SYNOPSIS
  +
  + # In Makefile.PL
  + use Apache::test;
  + my %params = Apache::test->get_test_params();
  + Apache::test->write_httpd_conf(%params, include => $more_directives);
  + *MY::test = sub { Apache::test->MM_test(%params) };
  +
  + # In t/*.t script (or test.pl)
  + (Some methods of Doug's that I haven't reviewed or documented yet)
  +
  +=head1 DESCRIPTION
  +
  +This module helps authors of Apache::* modules write test suites that
  +can query an actual running Apache server with mod_perl and their
  +modules loaded into it.  Its functionality is generally separated into
  +methods that go in a Makefile.PL to configure, start, and stop the
  +server, and methods that go in one of the test scripts to make HTTP
  +queries and manage the results.
  +
  +=head1 METHODS
  +
  +=head2 get_test_params()
  +
  +This will ask the user a few questions about where the httpd binary
  +is, and what user/group/port should be used when running the server.
  +It will return a hash of the information it discovers.  This hash is
  +suitable for passing to the C<write_httpd_conf()> method.
  +
  +=head2 write_httpd_conf(%params)
  +
  +This will write a basic C<httpd.conf> file suitable for starting a
  +HTTP server during the 'make test' stage.  A hash of key/value pairs
  +that affect the written file can be passed as arguments.  The
  +following keys are recognized:
  +
  +=over 4
  +
  +=item * conf_file
  +
  +The path to the file that will be created.  Default is 't/httpd.conf'.
  +
  +=item * port
  +
  +The port that the Apache server will listen on.
  +
  +=item * user
  +
  +The user that the Apache server will run as.
  +
  +=item * group
  +
  +The group that the Apache server will run as.
  +
  +=item * include
  +
  +Any additional text you want added at the end of the config file.
  +Typically you'll have some C<PerlModule> and C<Perl*Handler>
  +directives to pass control to the module you're testing.  The C<blib/>
  +directories will be added to the C<@INC> path when searching for
  +modules, so that's nice.
  +
  +=back
  +
  +=head2 MM_test(%params)
  +
  +This method helps write a Makefile that supports running a web server
  +during the 'make test' stage.  When you execute 'make test', 'make'
  +will run 'make start_httpd', 'make run_tests', and 'make kill_httpd'
  +in sequence.  You can also run these commands independently if you
  +want.
  +
  +Pass the hash of parameters returned by C<get_test_params()> as an
  +argument to C<MM_test()>.
  +
  +To patch into the ExtUtils::MakeMaker wizardry (voodoo?), typically
  +you'll do the following in your Makefile.PL:
  +
  +  *MY::test = sub { Apache::test->MM_test(%params) };
  +
  +=head1 EXAMPLES
  +
  +No good examples yet.  Examples are welcome.  In the meantime, see
  +L<http://forum.swarthmore.edu/~ken/modules/Apache-AuthCookie/> , which
  +I'm retrofitting to use Apache::test.
  +
  +=head1 TO DO
  +
  +The MM_test method doesn't try to be very smart, it just writes the
  +text that seems to work in my configuration.  I am morally against
  +using the 'make' command for installing Perl modules (though of course
  +I do it anyway), so I haven't looked into this very much.  Send bug
  +reports or better (patches).
  +
  +I've got lots of code in my Apache::AuthCookie module (etc.) that
  +assists in actually making the queries of the running server.  I plan
  +to add that to this module, but first I need to compare what's already
  +here that does the same stuff.
  +
  +=head1 KUDOS
  +
  +To Doug MacEachern for writing the first version of this module.
  +
  +To [EMAIL PROTECTED] (Rafael Kitover) for contributing the code to
  +parse existing httpd.conf files for --enable-shared=max and DSOs.
  +
  +=head1 CAVEATS
  +
  +Except for making sure that the mod_perl distribution itself can run
  +'make test' okay, I haven't tried very hard to keep compatibility with
  +older versions of this module.  In particular MM_test() has changed
  +and probably isn't usable in the old ways, since some of its
  +assumptions are gone.  But none of this was ever documented, and
  +MM_test() doesn't seem to actually be used anywhere in the mod_perl
  +disribution, so I don't feel so bad about it.
  +
  +=head1 AUTHOR
  +
  +Doug MacEachern (original version)
  +
  +Ken Williams (latest changes and this documentation)
  +
  +=cut
  +
  
  
  

Reply via email to