Also notice that I did a few tweaks to mp2 source to support new A-T features. so you need to apply it from modperl-2.0, but you can and should test in Apache-Test/ as well.
I did various tests including:
1. 'make test' from Apache-Test. o delete blib o delete local lib/Apache/TestConfigData.pm o delete global Apache/TestConfigData.pm 1a - interactive config should kick in first time 1b - second time it should run without interactive config 1c - run 'make install', o delete blib o delete local lib/Apache/TestConfigData.pm 'make test' should run without interactive config 1d - now remove the globally installed Apache/TestConfigData.pm, and run 't/TEST -httpd /path' interactive config shouldn't kick in
2. repeat 1 but replace 'make test' with 't/TEST'
3. 'make test' from modperl-2.0, first o delete local lib/Apache/TestConfigData.pm o delete global Apache/TestConfigData.pm 3a - interactive config shouldn't kick in first time, since we explicitly path -httpd behind the scenes 3b - 'make install' (which installs a custom config), now build mod_perl against a different httpd path, make sure that 'make test' uses that different httpd path and not the one from the custom config
4. custom config wasn't done during install of Apache-Test (e.g. rpm binary package). o delete global Apache/TestConfigData.pm pick some module which uses Apache-Test 4a. run 'make test' - interactive config should kick in make sure that it was saved in ~/.apache-test/Apache/TestConfigData.pm (because there is no global config) 4b. run 'make test' - interactive config should not kick in second time
5. -save option (test to be written) main issue is to avoid the situation when 'Apache/TestConfigData.pm' was written to a root owned directory and a non-root user is trying to -save (need to save into ~/.apache-test/Apache/TestConfigData.pm, if the custom_config_path returns a path owned by root).
ok here it the patch:
Index: Apache-Test/Makefile.PL =================================================================== RCS file: /home/cvs/httpd-test/perl-framework/Apache-Test/Makefile.PL,v retrieving revision 1.15 diff -u -r1.15 Makefile.PL --- Apache-Test/Makefile.PL 6 Jan 2004 19:17:59 -0000 1.15 +++ Apache-Test/Makefile.PL 7 Jan 2004 03:46:57 -0000 @@ -12,12 +12,14 @@
use ExtUtils::MakeMaker; use Symbol; +use File::Spec::Functions qw(catfile); +use FindBin;
use Apache::TestMM qw(test); #enable 'make test' +use Apache::TestRun;
my $VERSION;
- Apache::TestMM::filter_args();
my @scripts = qw(t/TEST); @@ -35,6 +37,8 @@ add_Apache__test_target(); }
+write_custom_config_file_stub();
+
WriteMakefile(
NAME => 'Apache::Test',
VERSION => $VERSION,
@@ -99,3 +103,17 @@
$string;
};
}
+
+# write the custom test file so it'll be copied to blib if updated
+# during 'make test' and then installed system-wide
+sub write_custom_config_file_stub {
+ # It doesn't matter whether it gets written under modperl-2.0/lib
+ # or Apache-Test/lib root, since Apache::TestRun uses the same
+ # logic and will update that file with real config data, which
+ # 'make install' will then pick and install system-wide
+ my $path = catfile $FindBin::Bin, "lib",
+ Apache::TestRun::CUSTOM_CONFIG_FILE;
+ # write an empty stub
+ Apache::TestRun::custom_config_write($path, '');
+}
+
Index: Apache-Test/lib/Apache/TestConfig.pm
===================================================================
RCS file: /home/cvs/httpd-test/perl-framework/Apache-Test/lib/Apache/TestConfig.pm,v
retrieving revision 1.192
diff -u -r1.192 TestConfig.pm
--- Apache-Test/lib/Apache/TestConfig.pm 5 Jan 2004 23:40:53 -0000 1.192
+++ Apache-Test/lib/Apache/TestConfig.pm 7 Jan 2004 03:46:58 -0000
@@ -17,6 +17,9 @@
use constant IS_MOD_PERL_2_BUILD => IS_MOD_PERL_2 &&
require Apache::Build && Apache::Build::IS_MOD_PERL_BUILD();
+use constant IS_APACHE_TEST_BUILD => + grep { -e "$_/lib/Apache/TestConfig.pm" } qw(. ..); + use Symbol (); use File::Copy (); use File::Find qw(finddepth); @@ -305,20 +308,6 @@
$vars->{target} ||= (WIN32 ? 'Apache.exe' : 'httpd');
- unless ($vars->{httpd}) { - #sbindir should be bin/ with the default layout - #but its eaiser to workaround apxs than fix apxs - for my $dir (map { $vars->{$_} } qw(sbindir bindir)) { - next unless defined $dir; - my $httpd = catfile $dir, $vars->{target}; - next unless -x $httpd; - $vars->{httpd} = $httpd; - last; - } - - $vars->{httpd} ||= $self->default_httpd; - } - if ($vars->{httpd}) { my @chunks = splitdir $vars->{httpd}; #handle both $prefix/bin/httpd and $prefix/Apache.exe @@ -1366,7 +1355,7 @@ } }
- my $exe = $vars->{apxs} || $vars->{httpd}; + my $exe = $vars->{apxs} || $vars->{httpd} || ''; # if httpd.conf is older than executable push @reasons, "$exe is newer than $vars->{t_conf_file}" Index: Apache-Test/lib/Apache/TestRun.pm =================================================================== RCS file: /home/cvs/httpd-test/perl-framework/Apache-Test/lib/Apache/TestRun.pm,v retrieving revision 1.131 diff -u -r1.131 TestRun.pm --- Apache-Test/lib/Apache/TestRun.pm 19 Dec 2003 09:16:14 -0000 1.131 +++ Apache-Test/lib/Apache/TestRun.pm 7 Jan 2004 03:46:58 -0000 @@ -11,20 +11,29 @@ use Apache::TestHarness (); use Apache::TestTrace;
+use Cwd; use File::Find qw(finddepth); -use File::Spec::Functions qw(catfile); +use File::Spec::Functions qw(catfile catdir); use File::Basename qw(basename dirname); use Getopt::Long qw(GetOptions); use Config;
+use constant IS_APACHE_TEST_BUILD => Apache::TestConfig::IS_APACHE_TEST_BUILD; + use constant STARTUP_TIMEOUT => 300; # secs (good for extreme debug cases) + +use constant CUSTOM_CONFIG_FILE => 'Apache/TestConfigData.pm'; + use subs qw(exit_shell exit_perl);
+my $original_command; +my $orig_cwd; + my %core_files = (); my %original_t_perms = ();
my @std_run = qw(start-httpd run-tests stop-httpd);
-my @others = qw(verbose configure clean help ssl http11 bugreport);
+my @others = qw(verbose configure clean help ssl http11 bugreport save);
my @flag_opts = (@std_run, @others);
my @string_opts = qw(order trace);
my @ostring_opts = qw(proxy ping);
@@ -57,9 +66,24 @@
'ssl' => 'run tests through ssl',
'proxy' => 'proxy requests (default proxy is localhost)',
'trace=T' => 'change tracing default to: warning, notice, info, debug, ...',
+ 'save' => 'save test paramaters into Apache::TestConfigData',
(map { $_, "\U$_\E url" } @request_opts),
);
+# variables stored in $Apache::TestConfigData::vars +my @data_vars_must = qw(httpd apxs); +my @data_vars_opt = qw(user group port); +# mapping from $Apache::TestConfigData::vars to $ENV settings +my %vars_to_env = ( + httpd => 'APACHE', + user => 'APACHE_USER', + group => 'APACHE_GROUP', + apxs => 'APXS', + port => 'APACHE_PORT', +); + +custom_config_load(); + sub fixup { #make sure we use an absolute path to perl #else Test::Harness uses the perl in our PATH @@ -435,6 +459,19 @@ $test_config->cmodules_configure; $test_config->generate_httpd_conf; $test_config->save; + + # save if + # 1) requested to save + # 2) no saved config yet + # 3) A-T build (since it'll override the global file) + # the only side-effect of (3) is that if config is changed during + # A-T build it'll change the global custom config if that exists, + # but it shouldn't affect normal users who won't do it more than once + if ($self->{opts}->{save} + or !$self->custom_config_exists() + or IS_APACHE_TEST_BUILD) { + $self->custom_config_save(); + } }
sub try_exit_opts { @@ -470,12 +507,17 @@ my $test_config = $self->{test_config};
unless ($test_config->{vars}->{httpd}) { - error "no test server configured, please specify an httpd or ". - ($test_config->{APXS} ? - "an apxs other than $test_config->{APXS}" : "apxs"). - " or put either in your PATH. For example:\n" . - "$0 -httpd /path/to/bin/httpd"; - exit_perl 0; + $self->opt_clean(1); + # this method restarts the whole program via exec + # so it never returns + $self->custom_config_first_time; + } + + # if we have gotten that far we know at least about the location + # of httpd, so let's save it if we haven't saved any custom + # configs yet + unless ($self->custom_config_exists()) { + $self->custom_config_save(); }
my $opts = $self->{opts}; @@ -541,6 +583,10 @@
sub new_test_config { my $self = shift; + for (@data_vars_must, @data_vars_opt) { + next unless $Apache::TestConfigData::vars->{$_}; + $self->{conf_opts}->{$_} ||= $Apache::TestConfigData::vars->{$_}; + } Apache::TestConfig->new($self->{conf_opts}); }
@@ -563,12 +609,10 @@ } close $sh;
- # reconstruct argv, preserve multiwords args, eg 'PerlTrace all' - my $argv = join " ", map { /^-/ ? $_ : qq['$_'] } @ARGV; - my $command = "ulimit -c unlimited; $0 $argv"; - warning "setting ulimit to allow core files\n$command"; - exec $command; - die "exec $command has failed"; # shouldn't be reached + $original_command = "ulimit -c unlimited; $original_command"; + warning "setting ulimit to allow core files\n$original_command"; + exec $original_command; + die "exec $original_command has failed"; # shouldn't be reached }
sub set_ulimit { @@ -587,6 +631,10 @@ sub run { my $self = shift;
+ # reconstruct argv, preserve multiwords args, eg 'PerlTrace all' + my $argv = join " ", map { /^-/ ? $_ : qq['$_'] } @ARGV; + $original_command = "$0 $argv"; + $orig_cwd = Cwd::cwd(); $self->set_ulimit; $self->set_env; #make sure these are always set
@@ -1087,6 +1135,324 @@ CORE::exit $_[0]; }
+# determine where the configuration file Apache/TestConfigData.pm +# lives. The order searched is: +# 1) $ENV{HOME}/.apache-test/ +# 2) in global @INC (if preconfigured already) +# 3) in local lib (for build times) +my $custom_config_path; +sub custom_config_path { + + return $custom_config_path if $custom_config_path; + + my @global_inc = (); + my @build_inc = (); + for (@INC) { + my $rel_dir = basename $_; + $rel_dir eq 'lib' ? push(@build_inc, $_) : push(@global_inc, $_); + } + + # XXX $ENV{HOME} isn't propagated in mod_perl + unshift @global_inc, catdir $ENV{HOME}, '.apache-test' if $ENV{HOME}; + + for (@global_inc, @build_inc) { + my $candidate = File::Spec->rel2abs(catfile $_, CUSTOM_CONFIG_FILE); + next unless -e $candidate; + return $custom_config_path = $candidate; + } + + return ''; +} + +sub custom_config_exists { + my $self = shift; + # custom config gets loaded via custom_config_load when this + # package is loaded. it's enough to check whether we have a custom + # config for 'httpd'. + my $httpd = $Apache::TestConfigData::vars->{httpd} || ''; + return $httpd && -e $httpd ? 1 : 0; +} + +sub custom_config_save { + my $self = shift; + my $vars = $self->{test_config}->{vars}; + my $conf_opts = $self->{conf_opts}; + my $config_dump = ''; + + # minimum httpd needs to be set + return 0 unless $vars->{httpd} or $Apache::TestConfigData::vars->{httpd}; + + # it doesn't matter how these vars were set (apxs may get set + # using the path to httpd, or the other way around) + for (@data_vars_must) { + next unless my $var = $vars->{$_} || $conf_opts->{$_}; + $config_dump .= qq{ '$_' => '$var',\n}; + } + + # save these vars only if they were explicitly set via command line + # options. For example if someone builds A-T as user 'foo', then + # installs it as root and we save it, all users will now try to + # configure under that user 'foo' which won't quite work. + for (@data_vars_opt) { + next unless my $var = $conf_opts->{$_}; + $config_dump .= qq{ '$_' => '$var',\n}; + } + + my $path; + # if A-T build always update the build file, regardless whether + # the global file already exists, since 'make install' will + # overwrite it + if (IS_APACHE_TEST_BUILD) { + $path = catfile $vars->{top_dir}, 'lib', CUSTOM_CONFIG_FILE; + } + elsif ($path = custom_config_path() ) { + # do nothing, the config file already exists (global) + debug "Found custom config '$path'"; + } + else { + # next try a global location, as if it was configured before + # Apache::Test's 'make install' + my $base = dirname dirname $INC{"Apache/TestRun.pm"}; + $path = catdir $base, CUSTOM_CONFIG_FILE; + } + + # check whether we can write to the directory of the chosen path + if ($path) { + # first make sure that the file is writable if it exists + # already (it might be non-writable if installed via EU::MM) + if (-e $path) { + my $mode = (stat _)[2]; + $mode |= 0200; + chmod $mode, $path; # it's ok if we fail + } + + # try to open for append + my $fh = Symbol::gensym; + if (open $fh, ">>$path") { + close $fh; + } + else { + $path = ''; # can't use that path to write custom config + } + } + + # if we have no path yet, try to use ~ + if (!$path and $ENV{HOME}) { + $path = catfile $ENV{HOME}, '.apache-test', CUSTOM_CONFIG_FILE; + } + + if ($path) { + custom_config_write($path, $config_dump); + return 1; + } + + return 0; # failed to write config XXX: should we croak? +} + +sub custom_config_write { + my($path, $config_dump) = @_; + + my $pkg = << "EOC"; +package Apache::TestConfigData; + +use strict; +use warnings; + +\$Apache::TestConfigData::vars = { +$config_dump +}; + +1; + +=head1 NAME + +Apache::TestConfigData - Configuration file for Apache::Test + +=cut +EOC + + debug "Writing custom config $path"; + require File::Path; + my $dir = dirname $path; + File::Path::mkpath($dir, 0, 0755) unless -e $dir; + my $fh = Symbol::gensym; + open $fh, ">$path" or die "Cannot open $path: $!"; + print $fh $pkg; + close $fh; +} + +sub custom_config_load { + debug "trying to load custom config data"; + + if (my $custom_config_path = custom_config_path()) { + debug "loading custom config path '$custom_config_path'"; + + require $custom_config_path; + + # %ENV overloads any custom saved config (command-line option will + # override any of these settings), though only if assigned + # some value (this is because Makefile will pass empty env + # vars if none were assigned) + for (@data_vars_must, @data_vars_opt) { + my $value = $ENV{ $vars_to_env{$_} }; + next unless defined $value and length $value; + $Apache::TestConfigData::vars->{$_} = $value; + } + } +} + +sub custom_config_first_time { + my $self = shift; + + my $test_config = $self->{test_config}; + my $vars = $test_config->{vars}; + + require ExtUtils::MakeMaker; + require File::Spec; + local *which = \&Apache::TestConfig::which; + + print qq[ + +We are now going to configure the Apache-Test framework. +This configuration process needs to be done only once. + +]; + + print qq[ + +First we need to know where the 'httpd' executable is located. +If you have more than one Apache server is installed, make sure +you supply the path to the one you are going to use for testing. +You can always override this setting at run time via the '-httpd' +option. For example: + + % t/TEST -httpd /path/to/alternative/httpd + +or via the environment variable APACHE. For example: + + % APACHE=/path/to/alternative/httpd t/TEST + +]; + + { + my %choices = (); + for (grep defined $_, + map({ catfile $vars->{$_}, $vars->{target} } qw(sbindir bindir)), + $test_config->default_httpd, which($vars->{target}), + $ENV{APACHE}, which('apache'), which('httpd'), + $ENV{APACHE2}, which('apache2'), which('httpd2')) { + $choices{$_}++ if -e $_ && -x _; + } + my $optional = 0; + my $wanted = 'httpd'; + $test_config->{vars}->{$wanted} = + _custom_config_prompt_path($wanted, \%choices, $optional); + } + + print qq[ + +Next we need to know where the 'apxs' script is located. This script +provides a lot of information about the apache installation, and makes +it easier to find things. However it's not available on all platforms, +therefore it's optional. If you don't have it installed it's not a +problem. Notice that if you have Apache 2.x installed that script +could be called as 'apxs2'. + +If you have more than one Apache server is installed, make sure you +supply the path to the apxs script you are going to use for testing. +You can always override this setting at run time via the '-apxs' +option. For example: + + % t/TEST -apxs /path/to/alternative/apxs + +or via the environment variable APACHE. For example: + + % APXS=/path/to/alternative/apxs t/TEST + +]; + { + my %choices = (); + for (grep defined $_, + map({ catfile $vars->{$_}, 'apxs' } qw(sbindir bindir)), + $test_config->default_apxs, + $ENV{APXS}, which('apxs'), + $ENV{APXS2}, which('apxs2')) { + $choices{$_}++ if -e $_ && -x _; + } + my $optional = 1; + my $wanted = 'apxs'; + $test_config->{vars}->{$wanted} = + _custom_config_prompt_path($wanted, \%choices, $optional); + } + + $self->custom_config_save(); + + # we probably could reconfigure on the fly ($self->configure), but + # the problem is various cached data which won't be refreshed. so + # the simplest is just to restart the run from scratch + chdir $orig_cwd; + warning "rerunning '$original_command' with new config opts"; + exec $original_command; + die "exec $original_command has failed"; # shouldn't be reached +} + +sub _custom_config_prompt_path { + my($wanted, $rh_choices, $optional) = @_; + + my $ans; + my $default = ''; + my $optional_str = $optional ? " (optional)" : ''; + my $prompt = + "\nPlease provide a full path to$optional_str '$wanted' executable"; + + my @choices = (); + if (%$rh_choices) { + $prompt .= " or choose from the following options:\n\n"; + my $c = 0; + for (sort keys %$rh_choices) { + $c++; + $prompt .= " [$c] $_\n"; + push @choices, $_; + } + $prompt .= " \n"; + $default = 1; # a wild guess + } + else { + $prompt .= ":\n\n"; + } + + while (1) { + $ans = ExtUtils::MakeMaker::prompt($prompt, $default); + + # convert the item number to the path + if ($ans =~ /^\s*(\d+)\s*$/) { + if ($1 > 0 and $choices[$1-1]) { + $ans = $choices[$1-1]; + } + else { + warn "The choice '$ans' doesn't exist\n"; + next; + } + } + + if ($optional) { + return '' unless $ans; + } + + unless (File::Spec->file_name_is_absolute($ans)) { + my $cwd = Cwd::cwd(); + warn "The path '$ans' is not an absolute path. " . + "Please specify an absolute path\n"; + next; + } + + warn("'$ans' doesn't exist\n"), next unless -e $ans; + warn("'$ans' is not executable\n"), next unless -x $ans; + + return $ans; + } +} + 1;
__END__ @@ -1162,6 +1528,44 @@ }
Notice that the extension is I<.c>, and not I<.so>. + +=head1 Saving options + +When C<Apache::Test> is first installed, it will save the +values of C<httpd>, C<port>, C<apxs>, C<user>, and C<group>, +if set, to a configuration file C<Apache::TestConfigData>. +This information will then be used in setting these options +for subsequent uses. + +The values stored in C<Apache::TestConfigData> can be overriden +temporarily either by setting the appropriate environment +variable or by giving the relevant option when the C<TEST> +script is run. If you want to save these options to +C<Apache::TestConfigData>, use the C<-save> flag when +running C<TEST>. + +If you are running C<Apache::Test> as a +user who does not have permission to alter the system +C<Apache::TestConfigData>, you can place your +own private configuration file F<TestConfigData.pm> +under C<$ENV{HOME}/.apache-test/Apache/>, +which C<Apache::Test> will use, if present. An example +of such a configuration file is + + # file $ENV{HOME}/.apache-test/Apache/TestConfigData.pm + package Apache::TestConfigData; + use strict; + use warnings; + use vars qw($vars); + + $vars = { + 'group' => 'me', + 'user' => 'myself', + 'port' => '8529', + 'httpd' => '/usr/local/apache/bin/httpd', + + }; + 1;
=head2 C<new_test_config>
Index: lib/Apache/.cvsignore =================================================================== RCS file: /home/cvs/modperl-2.0/lib/Apache/.cvsignore,v retrieving revision 1.2 diff -u -r1.2 .cvsignore --- lib/Apache/.cvsignore 5 Mar 2001 04:06:54 -0000 1.2 +++ lib/Apache/.cvsignore 7 Jan 2004 03:46:58 -0000 @@ -1,3 +1,4 @@ BuildConfig.pm FunctionTable.pm StructureTable.pm +TestConfigData.pm Index: lib/ModPerl/BuildMM.pm =================================================================== RCS file: /home/cvs/modperl-2.0/lib/ModPerl/BuildMM.pm,v retrieving revision 1.13 diff -u -r1.13 BuildMM.pm --- lib/ModPerl/BuildMM.pm 1 Dec 2003 04:00:35 -0000 1.13 +++ lib/ModPerl/BuildMM.pm 7 Jan 2004 03:46:58 -0000 @@ -231,6 +231,10 @@ #so it can be found for 'use Apache2 ()' next if $v =~ /Apache2\.pm$/;
+ # another module generated by A-T that needs to go to the + # normal @INC + next if $v =~ /TestConfigData\.pm$/; + #move everything else to the Apache2/ subdir #unless already specified with \$(INST_LIB) #or already in Apache2/
__________________________________________________________________ Stas Bekman JAm_pH ------> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com