Hi all,

Here's a resend of the Apache::test patch that I sent yesterday, this time
sent as type text/plain from a Unix mailer.  Rick Myers noted that the
version I sent before was encoded with Macintosh BinHex, which is probably
not the most appropriate choice for this list. ;-)

 -Ken
Index: test.pm
===================================================================
RCS file: /home/cvspublic/modperl/lib/Apache/test.pm,v
retrieving revision 1.16
diff -u -r1.16 test.pm
--- test.pm     2000/03/06 20:38:22     1.16
+++ test.pm     2000/07/17 05:18:12
@@ -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