diff options
Diffstat (limited to 'rt/lib/RT/Test/Apache.pm')
-rw-r--r-- | rt/lib/RT/Test/Apache.pm | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/rt/lib/RT/Test/Apache.pm b/rt/lib/RT/Test/Apache.pm new file mode 100644 index 000000000..b2733eadb --- /dev/null +++ b/rt/lib/RT/Test/Apache.pm @@ -0,0 +1,270 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Test::Apache; +use strict; +use warnings; + +my %MODULES = ( + '2.2' => { + "mod_perl" => [qw(authz_host env alias perl)], + "fastcgi" => [qw(authz_host env alias mime fastcgi)], + }, +); + +my $apache_module_prefix = $ENV{RT_TEST_APACHE_MODULES}; +my $apxs = + $ENV{RT_TEST_APXS} + || RT::Test->find_executable('apxs') + || RT::Test->find_executable('apxs2'); + +if ($apxs and not $apache_module_prefix) { + $apache_module_prefix = `$apxs -q LIBEXECDIR`; + chomp $apache_module_prefix; +} + +$apache_module_prefix ||= 'modules'; + +sub basic_auth { + my $self = shift; + my $passwd = File::Spec->rel2abs( File::Spec->catfile( + 't', 'data', 'configs', 'passwords' ) ); + + return <<"EOT"; + AuthType Basic + AuthName "restricted area" + AuthUserFile $passwd + Require user root +EOT +} + +sub start_server { + my ($self, %config) = @_; + my %tmp = %{$config{tmp}}; + my %info = $self->apache_server_info( %config ); + + RT::Test::diag(do { + open( my $fh, '<', $tmp{'config'}{'RT'} ) or die $!; + local $/; + <$fh> + }); + + my $tmpl = File::Spec->rel2abs( File::Spec->catfile( + 't', 'data', 'configs', + 'apache'. $info{'version'} .'+'. $config{variant} .'.conf' + ) ); + my %opt = ( + listen => $config{port}, + server_root => $info{'HTTPD_ROOT'} || $ENV{'HTTPD_ROOT'} + || Test::More::BAIL_OUT("Couldn't figure out server root"), + document_root => $RT::MasonComponentRoot, + tmp_dir => "$tmp{'directory'}", + rt_bin_path => $RT::BinPath, + rt_sbin_path => $RT::SbinPath, + rt_site_config => $ENV{'RT_SITE_CONFIG'}, + load_modules => $info{load_modules}, + basic_auth => $config{basic_auth} ? $self->basic_auth : "", + ); + foreach (qw(log pid lock)) { + $opt{$_ .'_file'} = File::Spec->catfile( + "$tmp{'directory'}", "apache.$_" + ); + } + + $tmp{'config'}{'apache'} = File::Spec->catfile( + "$tmp{'directory'}", "apache.conf" + ); + $self->process_in_file( + in => $tmpl, + out => $tmp{'config'}{'apache'}, + options => \%opt, + ); + + $self->fork_exec($info{'executable'}, '-f', $tmp{'config'}{'apache'}); + my $pid = do { + my $tries = 15; + while ( !-s $opt{'pid_file'} ) { + $tries--; + last unless $tries; + sleep 1; + } + my $pid_fh; + unless (-e $opt{'pid_file'} and open($pid_fh, '<', $opt{'pid_file'})) { + Test::More::BAIL_OUT("Couldn't start apache server, no pid file (unknown error)") + unless -e $opt{log_file}; + + open my $log, "<", $opt{log_file}; + my $error = do {local $/; <$log>}; + close $log; + $RT::Logger->error($error) if $error; + Test::More::BAIL_OUT("Couldn't start apache server!"); + } + + my $pid = <$pid_fh>; + chomp $pid; + $pid; + }; + + Test::More::ok($pid, "Started apache server #$pid"); + return $pid; +} + +sub apache_server_info { + my $self = shift; + my %res = @_; + + my $bin = $res{'executable'} = $ENV{'RT_TEST_APACHE'} + || $self->find_apache_server + || Test::More::BAIL_OUT("Couldn't find apache server, use RT_TEST_APACHE"); + + Test::More::BAIL_OUT( + "Couldn't find apache modules directory (set APXS= or RT_TEST_APACHE_MODULES=)" + ) unless -d $apache_module_prefix; + + + RT::Test::diag("Using '$bin' apache executable for testing"); + + my $info = `$bin -V`; + ($res{'version'}) = ($info =~ m{Server\s+version:\s+Apache/(\d+\.\d+)\.}); + Test::More::BAIL_OUT( + "Couldn't figure out version of the server" + ) unless $res{'version'}; + + my %opts = ($info =~ m/^\s*-D\s+([A-Z_]+?)(?:="(.*)")$/mg); + %res = (%res, %opts); + + $res{'modules'} = [ + map {s/^\s+//; s/\s+$//; $_} + grep $_ !~ /Compiled in modules/i, + split /\r*\n/, `$bin -l` + ]; + + Test::More::BAIL_OUT( + "Unsupported apache version $res{version}" + ) unless exists $MODULES{$res{version}}; + + Test::More::BAIL_OUT( + "Unsupported apache variant $res{variant}" + ) unless exists $MODULES{$res{version}}{$res{variant}}; + + my @mlist = @{$MODULES{$res{version}}{$res{variant}}}; + push @mlist, "authn_file", "auth_basic", "authz_user" if $res{basic_auth}; + + $res{'load_modules'} = ''; + foreach my $mod ( @mlist ) { + next if grep $_ =~ /^(mod_|)$mod\.c$/, @{ $res{'modules'} }; + + my $so_file = $apache_module_prefix."/mod_".$mod.".so"; + Test::More::BAIL_OUT( "Couldn't load $mod module (expected in $so_file)" ) + unless -f $so_file; + $res{'load_modules'} .= + "LoadModule ${mod}_module $so_file\n"; + } + return %res; +} + +sub find_apache_server { + my $self = shift; + return $_ foreach grep defined, + map RT::Test->find_executable($_), + qw(httpd apache apache2 apache1); + return undef; +} + +sub apache_mpm_type { + my $self = shift; + my $apache = $self->find_apache_server; + my $out = `$apache -l`; + if ( $out =~ /^\s*(worker|prefork|event|itk)\.c\s*$/m ) { + return $1; + } +} + +sub fork_exec { + my $self = shift; + + RT::Test::__disconnect_rt(); + my $pid = fork; + unless ( defined $pid ) { + die "cannot fork: $!"; + } elsif ( !$pid ) { + exec @_; + die "can't exec `". join(' ', @_) ."` program: $!"; + } else { + RT::Test::__reconnect_rt(); + return $pid; + } +} + +sub process_in_file { + my $self = shift; + my %args = ( in => undef, options => undef, @_ ); + + my $text = RT::Test->file_content( $args{'in'} ); + while ( my ($opt) = ($text =~ /\%\%(.+?)\%\%/) ) { + my $value = $args{'options'}{ lc $opt }; + die "no value for $opt" unless defined $value; + + $text =~ s/\%\%\Q$opt\E\%\%/$value/g; + } + + my ($out_fh, $out_conf); + unless ( $args{'out'} ) { + ($out_fh, $out_conf) = tempfile(); + } else { + $out_conf = $args{'out'}; + open( $out_fh, '>', $out_conf ) + or die "couldn't open '$out_conf': $!"; + } + print $out_fh $text; + seek $out_fh, 0, 0; + + return ($out_fh, $out_conf); +} + +1; |