Apache-Test

 view release on metacpan or  search on metacpan

lib/Apache/TestConfig.pm  view on Meta::CPAN

package Apache::TestConfig;

use strict;
use warnings FATAL => 'all';

use constant WIN32   => $^O eq 'MSWin32';
use constant OSX     => $^O eq 'darwin';
use constant CYGWIN  => $^O eq 'cygwin';
use constant NETWARE => $^O eq 'NetWare';
use constant SOLARIS => $^O eq 'solaris';
use constant AIX     => $^O eq 'aix';
use constant WINFU   => WIN32 || NETWARE;
use constant COLOR   => ($ENV{APACHE_TEST_COLOR} && -t STDOUT) ? 1 : 0;

use constant DEFAULT_PORT => 8529;

use constant IS_MOD_PERL_2       =>
    eval { require mod_perl2 } || 0;

use constant IS_MOD_PERL_2_BUILD => IS_MOD_PERL_2 &&
    eval { require Apache2::Build && Apache2::Build::IS_MOD_PERL_BUILD() };

use constant IS_APACHE_TEST_BUILD =>
    grep { -e "$_/lib/Apache/TestConfig.pm" }
         qw(Apache-Test . .. ../Apache-Test);

use lib ();
use File::Copy ();
use File::Find qw(finddepth);
use File::Basename qw(dirname);
use File::Path ();
use File::Spec::Functions qw(catfile abs2rel splitdir canonpath
                             catdir file_name_is_absolute devnull);
use Cwd qw(fastcwd);
use Socket ();
use Symbol ();

use Apache::TestConfigPerl ();
use Apache::TestConfigParse ();
use Apache::TestTrace;
use Apache::TestServer ();
use Apache::TestRun ();

use vars qw(%Usage);

%Usage = (
   top_dir          => 'top-level directory (default is $PWD)',
   t_dir            => 'the t/ test directory (default is $top_dir/t)',
   t_conf           => 'the conf/ test directory (default is $t_dir/conf)',
   t_logs           => 'the logs/ test directory (default is $t_dir/logs)',
   t_state          => 'the state/ test directory (default is $t_dir/state)',
   t_pid_file       => 'location of the pid file (default is $t_logs/httpd.pid)',
   t_conf_file      => 'test httpd.conf file (default is $t_conf/httpd.conf)',
   src_dir          => 'source directory to look for mod_foos.so',
   serverroot       => 'ServerRoot (default is $t_dir)',
   documentroot     => 'DocumentRoot (default is $ServerRoot/htdocs',
   port             => 'Port [port_number|select] (default ' . DEFAULT_PORT . ')',
   servername       => 'ServerName (default is localhost)',
   user             => 'User to run test server as (default is $USER)',
   group            => 'Group to run test server as (default is $GROUP)',
   bindir           => 'Apache bin/ dir (default is apxs -q BINDIR)',
   sbindir          => 'Apache sbin/ dir (default is apxs -q SBINDIR)',
   httpd            => 'server to use for testing (default is $bindir/httpd)',
   target           => 'name of server binary (default is apxs -q TARGET)',
   apxs             => 'location of apxs (default is from Apache2::BuildConfig)',
   startup_timeout  => 'seconds to wait for the server to start (default is 60)',
   httpd_conf       => 'inherit config from this file (default is apxs derived)',
   httpd_conf_extra => 'inherit additional config from this file',
   minclients       => 'minimum number of concurrent clients (default is 1)',
   maxclients       => 'maximum number of concurrent clients (default is minclients+1)',
   threadsperchild  => 'number of threads per child when using threaded MPMs (default is 10)',
   limitrequestline => 'global LimitRequestLine setting (default is 128)',
   perlpod          => 'location of perl pod documents (for testing downloads)',
   proxyssl_url     => 'url for testing ProxyPass / https (default is localhost)',
   sslca            => 'location of SSL CA (default is $t_conf/ssl/ca)',
   sslcaorg         => 'SSL CA organization to use for tests (default is asf)',
   sslproto         => 'SSL/TLS protocol version(s) to test',
   libmodperl       => 'path to mod_perl\'s .so (full or relative to LIBEXECDIR)',
   defines          => 'values to add as -D defines (for example, "VAR1 VAR2")',
   (map { $_ . '_module_name', "$_ module name"} qw(cgi ssl thread access auth php)),
);

my %filepath_conf_opts = map { $_ => 1 }
    qw(top_dir t_dir t_conf t_logs t_state t_pid_file t_conf_file src_dir serverroot
       documentroot bindir sbindir httpd apxs httpd_conf httpd_conf_extra
       perlpod sslca libmodperl);

sub conf_opt_is_a_filepath {
    my $opt = shift;
    $opt && exists $filepath_conf_opts{$opt};
}

sub usage {
    for my $hash (\%Usage) {
        for (sort keys %$hash){
            printf "  -%-18s %s\n", $_, $hash->{$_};
        }
    }
}

sub filter_args {
    my($args, $wanted_args) = @_;
    my(@pass, %keep);

    my @filter = @$args;

    if (ref($filter[0])) {
        push @pass, shift @filter;
    }

    while (@filter) {
        my $key = shift @filter;
        # optinal - or -- prefix
        if (defined $key && $key =~ /^-?-?(.+)/ && exists $wanted_args->{$1}) {
            if (@filter) {
                $keep{$1} = shift @filter;
            }
            else {
                die "key $1 requires a matching value";
            }
        }
        else {
            push @pass, $key;
        }
    }

    return (\@pass, \%keep);
}

my %passenv = map { $_,1 } qw{
    APACHE_TEST_APXS
    APACHE_TEST_HTTPD
    APACHE_TEST_GROUP
    APACHE_TEST_USER
    APACHE_TEST_PORT
};

sub passenv {
    \%passenv;
}

sub passenv_makestr {
    my @vars;

    for (sort keys %passenv) {

lib/Apache/TestConfig.pm  view on Meta::CPAN

                "supplied all the needed information to run the tests. " .
                "Please post lib/Apache2/BuildConfig.pm along with the " .
                "bug report";
        }

        $self->clean(1);

        error "You must explicitly specify -httpd and/or -apxs options, " .
            "or set \$ENV{APACHE_TEST_HTTPD} and \$ENV{APACHE_TEST_APXS}, " .
            "or set your \$PATH to include the httpd and apxs binaries.";
        Apache::TestRun::exit_perl(1);

    }
    else {
        debug "Using httpd: $vars->{httpd}";
    }

    $self->inherit_config; #see TestConfigParse.pm
    $self->configure_httpd_eapi; #must come after inherit_config

    $self->default_module(cgi    => [qw(mod_cgi mod_cgid)]);
    $self->default_module(thread => [qw(worker threaded)]);
    $self->default_module(ssl    => [qw(mod_ssl)]);
    $self->default_module(access => [qw(mod_access mod_authz_host)]);
    $self->default_module(auth   => [qw(mod_auth mod_auth_basic)]);
    $self->default_module(php    => [qw(sapi_apache2 mod_php4 mod_php5)]);

    $self->{server}->post_config;

    return $self;
}

sub default_module {
    my($self, $name, $choices) = @_;

    my $mname = $name . '_module_name';

    unless ($self->{vars}->{$mname}) {
        ($self->{vars}->{$mname}) = grep {
            $self->{modules}->{"$_.c"};
        } @$choices;

        $self->{vars}->{$mname} ||= $choices->[0];
    }

    $self->{vars}->{$name . '_module'} =
      $self->{vars}->{$mname} . '.c'
}

sub configure_apxs {
    my $self = shift;

    $self->{APXS} = $self->default_apxs;

    return unless $self->{APXS};

    $self->{APXS} =~ s{/}{\\}g if WIN32;

    my $vars = $self->{vars};

    $vars->{bindir}   ||= $self->apxs('BINDIR', 1);
    $vars->{sbindir}  ||= $self->apxs('SBINDIR');
    $vars->{target}   ||= $self->apxs('TARGET');
    $vars->{conf_dir} ||= $self->apxs('SYSCONFDIR');

    if ($vars->{conf_dir}) {
        $vars->{httpd_conf} ||= catfile $vars->{conf_dir}, 'httpd.conf';
    }
}

sub configure_httpd {
    my $self = shift;
    my $vars = $self->{vars};

    debug "configuring httpd";

    $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
        for (1,2) {
            pop @chunks;
            last unless @chunks;
            $self->{httpd_basedir} = catfile @chunks;
            last if -d "$self->{httpd_basedir}/bin";
        }
    }

    #cleanup httpd droppings
    my $sem = catfile $vars->{t_logs}, 'apache_runtime_status.sem';
    unless (-e $sem) {
        $self->clean_add_file($sem);
    }
}

sub configure_httpd_eapi {
    my $self = shift;
    my $vars = $self->{vars};

    #deal with EAPI_MM_CORE_PATH if defined.
    if (defined($self->{httpd_defines}->{EAPI_MM_CORE_PATH})) {
        my $path = $self->{httpd_defines}->{EAPI_MM_CORE_PATH};

        #ensure the directory exists
        my @chunks = splitdir $path;
        pop @chunks; #the file component of the path
        $path = catdir @chunks;
        unless (file_name_is_absolute $path) {
            $path = catdir $vars->{serverroot}, $path;
        }
        $self->gendir($path);
    }
}

sub configure_proxy {
    my $self = shift;
    my $vars = $self->{vars};

    #if we proxy to ourselves, must bump the maxclients
    if ($vars->{proxy} =~ /^on$/i) {
        unless ($vars->{maxclients_preset}) {
            $vars->{minclients}++;
            $vars->{maxclients}++;
            $vars->{maxspare}++;
            $vars->{startserversthreadedmpm} ++;
            $vars->{minclientsthreadedmpm} += $vars->{threadsperchild};
            $vars->{maxclientsthreadedmpm} += $vars->{threadsperchild};

lib/Apache/TestConfig.pm  view on Meta::CPAN


    $group;
}

sub default_user {
    return if WINFU;

    my $uid = $>;

    my $user = $ENV{APACHE_TEST_USER} || (getpwuid($uid) || "#$uid");

    if ($user eq 'root') {
        my $other = (getpwnam('nobody'))[0];
        if ($other) {
            $user = $other;
        }
        else {
            die "cannot run tests as User root";
            #XXX: prompt for another username
        }
    }

    return $user;
}

sub default_serveradmin {
    my $vars = shift->{vars};
    join '@', ($vars->{user} || 'unknown'), $vars->{servername};
}

sub default_apxs {
    my $self = shift;

    return $self->{vars}->{apxs} if $self->{vars}->{apxs};

    if (my $build_config = $self->modperl_build_config()) {
        return $build_config->{MP_APXS};
    }

    if ($ENV{APACHE_TEST_APXS}) {
        return $ENV{APACHE_TEST_APXS};
    }

    # look in PATH as a last resort
    if (my $apxs = which('apxs')) {
        return $apxs;
    } elsif ($apxs = which('apxs2')) {
        return $apxs;
    }
    
    return;
}

sub default_httpd {
    my $self = shift;

    my $vars = $self->{vars};

    if (my $build_config = $self->modperl_build_config()) {
        if (my $p = $build_config->{MP_AP_PREFIX}) {
            for my $bindir (qw(bin sbin)) {
                my $httpd = catfile $p, $bindir, $vars->{target};
                return $httpd if -e $httpd;
                # The executable on Win32 in Apache/2.2 is httpd.exe,
                # so try that if Apache.exe doesn't exist
                if (WIN32) {
                    $httpd = catfile $p, $bindir, 'httpd.EXE';
                    if (-e $httpd) {
                        $vars->{target} = 'httpd.EXE';
                        return $httpd;
                    }
                }
            }
        }
    }

    if ($ENV{APACHE_TEST_HTTPD}) {
        return $ENV{APACHE_TEST_HTTPD};
    }

    # look in PATH as a last resort
    if (my $httpd = which('httpd')) {
        return $httpd;
    } elsif ($httpd = which('httpd2')) {
        return $httpd;
    } elsif ($httpd = which('apache')) {
        return $httpd;
    } elsif ($httpd = which('apache2')) {
        return $httpd;
    }
    
    return;
}

my $localhost;

sub default_localhost {
    my $localhost_addr = pack('C4', 127, 0, 0, 1);
    gethostbyaddr($localhost_addr, Socket::AF_INET()) || 'localhost';
}

sub default_servername {
    my $self = shift;
    $localhost ||= $self->default_localhost;
    die "Can't figure out the default localhost's server name"
        unless $localhost;
}

# memoize the selected value (so we make sure that the same port is used
# via select). The problem is that select_first_port() is called 3 times after
# -clean, and it's possible that a lower port will get released
# between calls, leading to various places in the test suite getting a
# different base port selection.
#
# XXX: There is still a problem if two t/TEST's configure at the same
# time, so they both see the same port free, but only the first one to
# bind() will actually get the port. So there is a need in another
# check and reconfiguration just before the server starts.
#
my $port_memoized;
sub select_first_port {
    my $self = shift;

    my $port ||= $port_memoized || $ENV{APACHE_TEST_PORT}
        || $self->{vars}{port} || DEFAULT_PORT;

    # memoize
    $port_memoized = $port;

    return $port unless $port eq 'select';

    # port select mode: try to find another available port, take into
    # account that each instance of the test suite may use more than
    # one port for virtual hosts, therefore try to check ports in big
    # steps (20?).
    my $step  = 20;
    my $tries = 20;
    $port = DEFAULT_PORT;
    until (Apache::TestServer->port_available($port)) {
        unless (--$tries) {
            error "no ports available";
            error "tried ports @{[DEFAULT_PORT]} - $port in $step increments";
            return 0;
        }
        $port += $step;
    }

    info "the default base port is used, using base port $port instead"
        unless $port == DEFAULT_PORT;

    # memoize
    $port_memoized = $port;

    return $port;
}

my $remote_addr;

sub our_remote_addr {
    my $self = shift;
    my $name = $self->default_servername;
    my $iaddr = (gethostbyname($name))[-1];
    unless (defined $iaddr) {
        error "Can't resolve host: '$name' (check /etc/hosts)";
        exit 1;
    }
    $remote_addr ||= Socket::inet_ntoa($iaddr);
}

sub default_loopback {
    '127.0.0.1';
}

sub port {
    my($self, $module) = @_;

    unless ($module) {



( run in 2.079 seconds using v1.01-cache-2.11-cpan-2398b32b56e )