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 in2. 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 time5. -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
