From d429b2e8ae6d9793acfe95d581085470a4b71e7c Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 26 Aug 2010 06:32:41 +0000 Subject: [PATCH 1/3] Update Test::Nginx. --- test/inc/Module/AutoInstall.pm | 19 +- test/inc/Module/Install.pm | 214 +++++----- test/inc/Module/Install/AutoInstall.pm | 17 +- test/inc/Module/Install/Base.pm | 11 +- test/inc/Module/Install/Can.pm | 2 +- test/inc/Module/Install/Fetch.pm | 2 +- test/inc/Module/Install/Include.pm | 2 +- test/inc/Module/Install/Makefile.pm | 229 +++++++++-- test/inc/Module/Install/Metadata.pm | 267 ++++++++----- test/inc/Module/Install/Win32.pm | 2 +- test/inc/Module/Install/WriteAll.pm | 7 +- test/inc/Test/Builder.pm | 300 +++----------- test/inc/Test/Builder/Module.pm | 18 +- test/inc/Test/More.pm | 45 +-- test/lib/Test/Nginx.pm | 72 +++- test/lib/Test/Nginx/Echo.pm | 520 ------------------------- test/lib/Test/Nginx/LWP.pm | 2 +- test/lib/Test/Nginx/Socket.pm | 74 +++- test/lib/Test/Nginx/Util.pm | 221 +++++++++-- 19 files changed, 961 insertions(+), 1063 deletions(-) delete mode 100644 test/lib/Test/Nginx/Echo.pm diff --git a/test/inc/Module/AutoInstall.pm b/test/inc/Module/AutoInstall.pm index dfb8ef7..60b90ea 100644 --- a/test/inc/Module/AutoInstall.pm +++ b/test/inc/Module/AutoInstall.pm @@ -253,6 +253,8 @@ sub import { # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; + + return (@Existing, @Missing); } sub _running_under { @@ -672,7 +674,20 @@ sub _load { sub _load_cpan { return if $CPAN::VERSION and $CPAN::Config and not @_; require CPAN; - if ( $CPAN::HandleConfig::VERSION ) { + + # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to + # CPAN::HandleConfig->load. CPAN reports that the redirection + # is deprecated in a warning printed at the user. + + # CPAN-1.81 expects CPAN::HandleConfig->load, does not have + # $CPAN::HandleConfig::VERSION but cannot handle + # CPAN::Config->load + + # Which "versions expect CPAN::Config->load? + + if ( $CPAN::HandleConfig::VERSION + || CPAN::HandleConfig->can('load') + ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { @@ -802,4 +817,4 @@ END_MAKE __END__ -#line 1056 +#line 1071 diff --git a/test/inc/Module/Install.pm b/test/inc/Module/Install.pm index 51eda5d..af32a30 100644 --- a/test/inc/Module/Install.pm +++ b/test/inc/Module/Install.pm @@ -19,6 +19,9 @@ package Module::Install; use 5.005; use strict 'vars'; +use Cwd (); +use File::Find (); +use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { @@ -28,7 +31,7 @@ BEGIN { # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. - $VERSION = '0.91'; + $VERSION = '0.99'; # Storage for the pseudo-singleton $MAIN = undef; @@ -38,18 +41,25 @@ BEGIN { } +sub import { + my $class = shift; + my $self = $class->new(@_); + my $who = $self->_caller; - - - -# Whether or not inc::Module::Install is actually loaded, the -# $INC{inc/Module/Install.pm} is what will still get set as long as -# the caller loaded module this in the documented manner. -# If not set, the caller may NOT have loaded the bundled version, and thus -# they may not have a MI version that works with the Makefile.PL. This would -# result in false errors or unexpected behaviour. And we don't want that. -my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; -unless ( $INC{$file} ) { die <<"END_DIE" } + #------------------------------------------------------------- + # all of the following checks should be included in import(), + # to allow "eval 'require Module::Install; 1' to test + # installation of Module::Install. (RT #51267) + #------------------------------------------------------------- + + # Whether or not inc::Module::Install is actually loaded, the + # $INC{inc/Module/Install.pm} is what will still get set as long as + # the caller loaded module this in the documented manner. + # If not set, the caller may NOT have loaded the bundled version, and thus + # they may not have a MI version that works with the Makefile.PL. This would + # result in false errors or unexpected behaviour. And we don't want that. + my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; + unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: @@ -61,26 +71,28 @@ not: END_DIE - - - - -# If the script that is loading Module::Install is from the future, -# then make will detect this and cause it to re-run over and over -# again. This is bad. Rather than taking action to touch it (which -# is unreliable on some platforms and requires write permissions) -# for now we should catch this and refuse to run. -if ( -f $0 ) { - my $s = (stat($0))[9]; - - # If the modification time is only slightly in the future, - # sleep briefly to remove the problem. - my $a = $s - time; - if ( $a > 0 and $a < 5 ) { sleep 5 } - - # Too far in the future, throw an error. - my $t = time; - if ( $s > $t ) { die <<"END_DIE" } + # This reportedly fixes a rare Win32 UTC file time issue, but + # as this is a non-cross-platform XS module not in the core, + # we shouldn't really depend on it. See RT #24194 for detail. + # (Also, this module only supports Perl 5.6 and above). + eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; + + # If the script that is loading Module::Install is from the future, + # then make will detect this and cause it to re-run over and over + # again. This is bad. Rather than taking action to touch it (which + # is unreliable on some platforms and requires write permissions) + # for now we should catch this and refuse to run. + if ( -f $0 ) { + my $s = (stat($0))[9]; + + # If the modification time is only slightly in the future, + # sleep briefly to remove the problem. + my $a = $s - time; + if ( $a > 0 and $a < 5 ) { sleep 5 } + + # Too far in the future, throw an error. + my $t = time; + if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). @@ -89,15 +101,12 @@ This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE -} - - - + } -# Build.PL was formerly supported, but no longer is due to excessive -# difficulty in implementing every single feature twice. -if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } + # Build.PL was formerly supported, but no longer is due to excessive + # difficulty in implementing every single feature twice. + if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. @@ -107,23 +116,42 @@ Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE + #------------------------------------------------------------- + # To save some more typing in Module::Install installers, every... + # use inc::Module::Install + # ...also acts as an implicit use strict. + $^H |= strict::bits(qw(refs subs vars)); + #------------------------------------------------------------- + unless ( -f $self->{file} ) { + foreach my $key (keys %INC) { + delete $INC{$key} if $key =~ /Module\/Install/; + } -# To save some more typing in Module::Install installers, every... -# use inc::Module::Install -# ...also acts as an implicit use strict. -$^H |= strict::bits(qw(refs subs vars)); - + local $^W; + require "$self->{path}/$self->{dispatch}.pm"; + File::Path::mkpath("$self->{prefix}/$self->{author}"); + $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); + $self->{admin}->init; + @_ = ($class, _self => $self); + goto &{"$self->{name}::import"}; + } + local $^W; + *{"${who}::AUTOLOAD"} = $self->autoload; + $self->preload; + # Unregister loader and worker packages so subdirs can use them again + delete $INC{'inc/Module/Install.pm'}; + delete $INC{'Module/Install.pm'}; + # Save to the singleton + $MAIN = $self; -use Cwd (); -use File::Find (); -use File::Path (); -use FindBin; + return 1; +} sub autoload { my $self = shift; @@ -136,7 +164,21 @@ sub autoload { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } - $$sym =~ /([^:]+)$/ or die "Cannot autoload $who - $sym"; + unless ($$sym =~ s/([^:]+)$//) { + # XXX: it looks like we can't retrieve the missing function + # via $$sym (usually $main::AUTOLOAD) in this case. + # I'm still wondering if we should slurp Makefile.PL to + # get some context or not ... + my ($package, $file, $line) = caller; + die <<"EOT"; +Unknown function is found at $file line $line. +Execution of $file aborted due to runtime errors. + +If you're a contributor to a project, you may need to install +some Module::Install extensions from CPAN (or other repository). +If you're a user of a module, please contact the author. +EOT + } my $method = $1; if ( uc($method) eq $method ) { # Do nothing @@ -152,33 +194,6 @@ sub autoload { }; } -sub import { - my $class = shift; - my $self = $class->new(@_); - my $who = $self->_caller; - - unless ( -f $self->{file} ) { - require "$self->{path}/$self->{dispatch}.pm"; - File::Path::mkpath("$self->{prefix}/$self->{author}"); - $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); - $self->{admin}->init; - @_ = ($class, _self => $self); - goto &{"$self->{name}::import"}; - } - - *{"${who}::AUTOLOAD"} = $self->autoload; - $self->preload; - - # Unregister loader and worker packages so subdirs can use them again - delete $INC{"$self->{file}"}; - delete $INC{"$self->{path}.pm"}; - - # Save to the singleton - $MAIN = $self; - - return 1; -} - sub preload { my $self = shift; unless ( $self->{extensions} ) { @@ -204,6 +219,7 @@ sub preload { my $who = $self->_caller; foreach my $name ( sort keys %seen ) { + local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; @@ -214,12 +230,14 @@ sub preload { sub new { my ($class, %args) = @_; + delete $INC{'FindBin.pm'}; + require FindBin; + # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) { delete $args{prefix}; } - return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; @@ -272,8 +290,10 @@ END_DIE sub load_extensions { my ($self, $path, $top) = @_; + my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; + $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { @@ -281,12 +301,13 @@ sub load_extensions { next if $self->{pathnames}{$pkg}; local $@; - my $new = eval { require $file; $pkg->can('new') }; + my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } - $self->{pathnames}{$pkg} = delete $INC{$file}; + $self->{pathnames}{$pkg} = + $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } @@ -348,17 +369,24 @@ sub _caller { return $call; } +# Done in evals to avoid confusing Perl::MinimumVersion +eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _read { local *FH; - if ( $] >= 5.006 ) { - open( FH, '<', $_[0] ) or die "open($_[0]): $!"; - } else { - open( FH, "< $_[0]" ) or die "open($_[0]): $!"; - } + open( FH, '<', $_[0] ) or die "open($_[0]): $!"; + my $string = do { local $/; }; + close FH or die "close($_[0]): $!"; + return $string; +} +END_NEW +sub _read { + local *FH; + open( FH, "< $_[0]" ) or die "open($_[0]): $!"; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } +END_OLD sub _readperl { my $string = Module::Install::_read($_[0]); @@ -379,18 +407,26 @@ sub _readpod { return $string; } +# Done in evals to avoid confusing Perl::MinimumVersion +eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _write { local *FH; - if ( $] >= 5.006 ) { - open( FH, '>', $_[0] ) or die "open($_[0]): $!"; - } else { - open( FH, "> $_[0]" ) or die "open($_[0]): $!"; + open( FH, '>', $_[0] ) or die "open($_[0]): $!"; + foreach ( 1 .. $#_ ) { + print FH $_[$_] or die "print($_[0]): $!"; } + close FH or die "close($_[0]): $!"; +} +END_NEW +sub _write { + local *FH; + open( FH, "> $_[0]" ) or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } +END_OLD # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). @@ -427,4 +463,4 @@ sub _CLASS ($) { 1; -# Copyright 2008 - 2009 Adam Kennedy. +# Copyright 2008 - 2010 Adam Kennedy. diff --git a/test/inc/Module/Install/AutoInstall.pm b/test/inc/Module/Install/AutoInstall.pm index 58dd026..aa9f258 100644 --- a/test/inc/Module/Install/AutoInstall.pm +++ b/test/inc/Module/Install/AutoInstall.pm @@ -6,7 +6,7 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } @@ -37,12 +37,25 @@ sub auto_install { $self->include('Module::AutoInstall'); require Module::AutoInstall; - Module::AutoInstall->import( + my @features_require = Module::AutoInstall->import( (@config ? (-config => \@config) : ()), (@core ? (-core => \@core) : ()), $self->features, ); + my %seen; + my @requires = map @$_, map @$_, grep ref, $self->requires; + while (my ($mod, $ver) = splice(@requires, 0, 2)) { + $seen{$mod}{$ver}++; + } + + my @deduped; + while (my ($mod, $ver) = splice(@features_require, 0, 2)) { + push @deduped, $mod => $ver unless $seen{$mod}{$ver}++; + } + + $self->requires(@deduped); + $self->makemaker_args( Module::AutoInstall::_make_args() ); my $class = ref($self); diff --git a/test/inc/Module/Install/Base.pm b/test/inc/Module/Install/Base.pm index 60a74d2..c86c197 100644 --- a/test/inc/Module/Install/Base.pm +++ b/test/inc/Module/Install/Base.pm @@ -4,7 +4,7 @@ package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; } # Suspend handler for "redefined" warnings @@ -51,13 +51,18 @@ sub admin { #line 106 sub is_admin { - $_[0]->admin->VERSION; + ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; +use vars qw{$VERSION}; +BEGIN { + $VERSION = $Module::Install::Base::VERSION; +} + my $fake; sub new { @@ -75,4 +80,4 @@ BEGIN { 1; -#line 154 +#line 159 diff --git a/test/inc/Module/Install/Can.pm b/test/inc/Module/Install/Can.pm index e65e4f6..994dd3f 100644 --- a/test/inc/Module/Install/Can.pm +++ b/test/inc/Module/Install/Can.pm @@ -9,7 +9,7 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } diff --git a/test/inc/Module/Install/Fetch.pm b/test/inc/Module/Install/Fetch.pm index 05f2079..df357b2 100644 --- a/test/inc/Module/Install/Fetch.pm +++ b/test/inc/Module/Install/Fetch.pm @@ -6,7 +6,7 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } diff --git a/test/inc/Module/Install/Include.pm b/test/inc/Module/Install/Include.pm index 7e792e0..1aa5589 100644 --- a/test/inc/Module/Install/Include.pm +++ b/test/inc/Module/Install/Include.pm @@ -6,7 +6,7 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } diff --git a/test/inc/Module/Install/Makefile.pm b/test/inc/Module/Install/Makefile.pm index 98779db..a3536a4 100644 --- a/test/inc/Module/Install/Makefile.pm +++ b/test/inc/Module/Install/Makefile.pm @@ -4,10 +4,11 @@ package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); +use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } @@ -25,8 +26,8 @@ sub prompt { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } - # In automated testing, always use defaults - if ( $ENV{AUTOMATED_TESTING} and ! $ENV{PERL_MM_USE_DEFAULT} ) { + # In automated testing or non-interactive session, always use defaults + if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { @@ -34,21 +35,112 @@ sub prompt { } } +# Store a cleaned up version of the MakeMaker version, +# since we need to behave differently in a variety of +# ways based on the MM version. +my $makemaker = eval $ExtUtils::MakeMaker::VERSION; + +# If we are passed a param, do a "newer than" comparison. +# Otherwise, just return the MakeMaker version. +sub makemaker { + ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 +} + +# Ripped from ExtUtils::MakeMaker 6.56, and slightly modified +# as we only need to know here whether the attribute is an array +# or a hash or something else (which may or may not be appendable). +my %makemaker_argtype = ( + C => 'ARRAY', + CONFIG => 'ARRAY', +# CONFIGURE => 'CODE', # ignore + DIR => 'ARRAY', + DL_FUNCS => 'HASH', + DL_VARS => 'ARRAY', + EXCLUDE_EXT => 'ARRAY', + EXE_FILES => 'ARRAY', + FUNCLIST => 'ARRAY', + H => 'ARRAY', + IMPORTS => 'HASH', + INCLUDE_EXT => 'ARRAY', + LIBS => 'ARRAY', # ignore '' + MAN1PODS => 'HASH', + MAN3PODS => 'HASH', + META_ADD => 'HASH', + META_MERGE => 'HASH', + PL_FILES => 'HASH', + PM => 'HASH', + PMLIBDIRS => 'ARRAY', + PMLIBPARENTDIRS => 'ARRAY', + PREREQ_PM => 'HASH', + CONFIGURE_REQUIRES => 'HASH', + SKIP => 'ARRAY', + TYPEMAPS => 'ARRAY', + XS => 'HASH', +# VERSION => ['version',''], # ignore +# _KEEP_AFTER_FLUSH => '', + + clean => 'HASH', + depend => 'HASH', + dist => 'HASH', + dynamic_lib=> 'HASH', + linkext => 'HASH', + macro => 'HASH', + postamble => 'HASH', + realclean => 'HASH', + test => 'HASH', + tool_autosplit => 'HASH', + + # special cases where you can use makemaker_append + CCFLAGS => 'APPENDABLE', + DEFINE => 'APPENDABLE', + INC => 'APPENDABLE', + LDDLFLAGS => 'APPENDABLE', + LDFROM => 'APPENDABLE', +); + sub makemaker_args { - my $self = shift; + my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); - %$args = ( %$args, @_ ); + foreach my $key (keys %new_args) { + if ($makemaker_argtype{$key}) { + if ($makemaker_argtype{$key} eq 'ARRAY') { + $args->{$key} = [] unless defined $args->{$key}; + unless (ref $args->{$key} eq 'ARRAY') { + $args->{$key} = [$args->{$key}] + } + push @{$args->{$key}}, + ref $new_args{$key} eq 'ARRAY' + ? @{$new_args{$key}} + : $new_args{$key}; + } + elsif ($makemaker_argtype{$key} eq 'HASH') { + $args->{$key} = {} unless defined $args->{$key}; + foreach my $skey (keys %{ $new_args{$key} }) { + $args->{$key}{$skey} = $new_args{$key}{$skey}; + } + } + elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { + $self->makemaker_append($key => $new_args{$key}); + } + } + else { + if (defined $args->{$key}) { + warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; + } + $args->{$key} = $new_args{$key}; + } + } return $args; } # For mm args that take multiple space-seperated args, # append an argument to the current list. sub makemaker_append { - my $self = sShift; + my $self = shift; my $name = shift; my $args = $self->makemaker_args; - $args->{name} = defined $args->{$name} - ? join( ' ', $args->{name}, @_ ) + $args->{$name} = defined $args->{$name} + ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } @@ -89,25 +181,22 @@ sub inc { $self->makemaker_args( INC => shift ); } -my %test_dir = (); - sub _wanted_t { - /\.t$/ and -f $_ and $test_dir{$File::Find::dir} = 1; } sub tests_recursive { my $self = shift; - if ( $self->tests ) { - die "tests_recursive will not work if tests are already defined"; - } my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } - %test_dir = (); + my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; - File::Find::find( \&_wanted_t, $dir ); - $self->tests( join ' ', map { "$_/*.t" } sort keys %test_dir ); + File::Find::find( + sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, + $dir + ); + $self->tests( join ' ', sort keys %tests ); } sub write { @@ -130,12 +219,13 @@ sub write { # an underscore, even though its own version may contain one! # Hence the funny regexp to get rid of it. See RT #35800 # for details. - $self->build_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ ); - $self->configure_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ ); + my $v = $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/; + $self->build_requires( 'ExtUtils::MakeMaker' => $v ); + $self->configure_requires( 'ExtUtils::MakeMaker' => $v ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. - $self->build_requires( 'ExtUtils::MakeMaker' => 6.42 ); + $self->build_requires( 'ExtUtils::MakeMaker' => 6.42 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.42 ); } @@ -143,59 +233,115 @@ sub write { my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; - $args->{VERSION} = $self->version; $args->{NAME} =~ s/-/::/g; + $args->{VERSION} = $self->version or die <<'EOT'; +ERROR: Can't determine distribution version. Please specify it +explicitly via 'version' in Makefile.PL, or set a valid $VERSION +in a module, and provide its file path via 'version_from' (or +'all_from' if you prefer) in Makefile.PL. +EOT + + $DB::single = 1; if ( $self->tests ) { - $args->{test} = { TESTS => $self->tests }; + my @tests = split ' ', $self->tests; + my %seen; + $args->{test} = { + TESTS => (join ' ', grep {!$seen{$_}++} @tests), + }; + } elsif ( $Module::Install::ExtraTests::use_extratests ) { + # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. + # So, just ignore our xt tests here. + } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { + $args->{test} = { + TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), + }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; - $args->{AUTHOR} = $self->author; + $args->{AUTHOR} = join ', ', @{$self->author || []}; } - if ( eval($ExtUtils::MakeMaker::VERSION) >= 6.10 ) { - $args->{NO_META} = 1; + if ( $self->makemaker(6.10) ) { + $args->{NO_META} = 1; + #$args->{NO_MYMETA} = 1; } - if ( eval($ExtUtils::MakeMaker::VERSION) > 6.17 and $self->sign ) { + if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } + if ( $self->makemaker(6.31) and $self->license ) { + $args->{LICENSE} = $self->license; + } - # Merge both kinds of requires into prereq_pm my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, - map { @$_ } + map { @$_ } # flatten [module => version] map { @$_ } grep $_, - ($self->configure_requires, $self->build_requires, $self->requires) + ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; - # merge both kinds of requires into prereq_pm - my $subdirs = ($args->{DIR} ||= []); + # Merge both kinds of requires into BUILD_REQUIRES + my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); + %$build_prereq = ( %$build_prereq, + map { @$_ } # flatten [module => version] + map { @$_ } + grep $_, + ($self->configure_requires, $self->build_requires) + ); + + # Remove any reference to perl, BUILD_REQUIRES doesn't support it + delete $args->{BUILD_REQUIRES}->{perl}; + + # Delete bundled dists from prereq_pm, add it to Makefile DIR + my $subdirs = ($args->{DIR} || []); if ($self->bundles) { + my %processed; foreach my $bundle (@{ $self->bundles }) { - my ($file, $dir) = @$bundle; - push @$subdirs, $dir if -d $dir; - delete $prereq->{$file}; + my ($mod_name, $dist_dir) = @$bundle; + delete $prereq->{$mod_name}; + $dist_dir = File::Basename::basename($dist_dir); # dir for building this module + if (not exists $processed{$dist_dir}) { + if (-d $dist_dir) { + # List as sub-directory to be processed by make + push @$subdirs, $dist_dir; + } + # Else do nothing: the module is already present on the system + $processed{$dist_dir} = undef; + } } } + unless ( $self->makemaker('6.55_03') ) { + %$prereq = (%$prereq,%$build_prereq); + delete $args->{BUILD_REQUIRES}; + } + if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; + + if ( $self->makemaker(6.48) ) { + $args->{MIN_PERL_VERSION} = $perl_version; + } } - $args->{INSTALLDIRS} = $self->installdirs; + if ($self->installdirs) { + warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; + $args->{INSTALLDIRS} = $self->installdirs; + } - my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_})} keys %$args; + my %args = map { + ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) + } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; - if (my $preop = $self->admin->preop($user_preop)) { + if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } @@ -219,9 +365,9 @@ sub fix_up_makefile { . ($self->postamble || ''); local *MAKEFILE; - open MAKEFILE, "< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; + open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; + eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; - close MAKEFILE or die $!; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; @@ -241,7 +387,8 @@ sub fix_up_makefile { # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; - open MAKEFILE, "> $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; + seek MAKEFILE, 0, SEEK_SET; + truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; @@ -265,4 +412,4 @@ sub postamble { __END__ -#line 394 +#line 541 diff --git a/test/inc/Module/Install/Metadata.pm b/test/inc/Module/Install/Metadata.pm index 653193d..bdeb367 100644 --- a/test/inc/Module/Install/Metadata.pm +++ b/test/inc/Module/Install/Metadata.pm @@ -6,7 +6,7 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } @@ -19,7 +19,6 @@ my @scalar_keys = qw{ name module_name abstract - author version distribution_type tests @@ -43,8 +42,11 @@ my @resource_keys = qw{ my @array_keys = qw{ keywords + author }; +*authors = \&author; + sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } @@ -176,43 +178,6 @@ sub perl_version { $self->{values}->{perl_version} = $version; } -#Stolen from M::B -my %license_urls = ( - perl => 'http://dev.perl.org/licenses/', - apache => 'http://apache.org/licenses/LICENSE-2.0', - artistic => 'http://opensource.org/licenses/artistic-license.php', - artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', - lgpl => 'http://opensource.org/licenses/lgpl-license.php', - lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', - lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', - bsd => 'http://opensource.org/licenses/bsd-license.php', - gpl => 'http://opensource.org/licenses/gpl-license.php', - gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', - gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', - mit => 'http://opensource.org/licenses/mit-license.php', - mozilla => 'http://opensource.org/licenses/mozilla1.1.php', - open_source => undef, - unrestricted => undef, - restrictive => undef, - unknown => undef, -); - -sub license { - my $self = shift; - return $self->{values}->{license} unless @_; - my $license = shift or die( - 'Did not provide a value to license()' - ); - $self->{values}->{license} = $license; - - # Automatically fill in license URLs - if ( $license_urls{$license} ) { - $self->resources( license => $license_urls{$license} ); - } - - return 1; -} - sub all_from { my ( $self, $file ) = @_; @@ -230,6 +195,8 @@ sub all_from { die("The path '$file' does not exist, or is not a file"); } + $self->{values}{all_from} = $file; + # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; @@ -240,7 +207,7 @@ sub all_from { $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; - $self->author_from($pod) unless $self->author; + $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; @@ -350,6 +317,9 @@ sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); + + # for version integrity check + $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { @@ -360,7 +330,7 @@ sub abstract_from { { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) - ); + ); } # Add both distribution and module name @@ -385,11 +355,10 @@ sub name_from { } } -sub perl_version_from { - my $self = shift; +sub _extract_perl_version { if ( - Module::Install::_read($_[0]) =~ m/ - ^ + $_[0] =~ m/ + ^\s* (?:use|require) \s* v? ([\d_\.]+) @@ -398,6 +367,16 @@ sub perl_version_from { ) { my $perl_version = $1; $perl_version =~ s{_}{}g; + return $perl_version; + } else { + return; + } +} + +sub perl_version_from { + my $self = shift; + my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); + if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; @@ -417,59 +396,164 @@ sub author_from { ([^\n]*) /ixms) { my $author = $1 || $2; - $author =~ s{E}{<}g; - $author =~ s{E}{>}g; + + # XXX: ugly but should work anyway... + if (eval "require Pod::Escapes; 1") { + # Pod::Escapes has a mapping table. + # It's in core of perl >= 5.9.3, and should be installed + # as one of the Pod::Simple's prereqs, which is a prereq + # of Pod::Text 3.x (see also below). + $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } + { + defined $2 + ? chr($2) + : defined $Pod::Escapes::Name2character_number{$1} + ? chr($Pod::Escapes::Name2character_number{$1}) + : do { + warn "Unknown escape: E<$1>"; + "E<$1>"; + }; + }gex; + } + elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { + # Pod::Text < 3.0 has yet another mapping table, + # though the table name of 2.x and 1.x are different. + # (1.x is in core of Perl < 5.6, 2.x is in core of + # Perl < 5.9.3) + my $mapping = ($Pod::Text::VERSION < 2) + ? \%Pod::Text::HTML_Escapes + : \%Pod::Text::ESCAPES; + $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } + { + defined $2 + ? chr($2) + : defined $mapping->{$1} + ? $mapping->{$1} + : do { + warn "Unknown escape: E<$1>"; + "E<$1>"; + }; + }gex; + } + else { + $author =~ s{E}{<}g; + $author =~ s{E}{>}g; + } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } -sub license_from { +#Stolen from M::B +my %license_urls = ( + perl => 'http://dev.perl.org/licenses/', + apache => 'http://apache.org/licenses/LICENSE-2.0', + apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', + artistic => 'http://opensource.org/licenses/artistic-license.php', + artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', + lgpl => 'http://opensource.org/licenses/lgpl-license.php', + lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', + lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', + bsd => 'http://opensource.org/licenses/bsd-license.php', + gpl => 'http://opensource.org/licenses/gpl-license.php', + gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', + gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', + mit => 'http://opensource.org/licenses/mit-license.php', + mozilla => 'http://opensource.org/licenses/mozilla1.1.php', + open_source => undef, + unrestricted => undef, + restrictive => undef, + unknown => undef, +); + +sub license { my $self = shift; - if ( - Module::Install::_read($_[0]) =~ m/ - ( - =head \d \s+ - (?:licen[cs]e|licensing|copyright|legal)\b - .*? - ) - (=head\\d.*|=cut.*|) - \z - /ixms ) { - my $license_text = $1; - my @phrases = ( - 'under the same (?:terms|license) as (?:perl|the perl programming language) itself' => 'perl', 1, - 'GNU general public license' => 'gpl', 1, - 'GNU public license' => 'gpl', 1, - 'GNU lesser general public license' => 'lgpl', 1, - 'GNU lesser public license' => 'lgpl', 1, - 'GNU library general public license' => 'lgpl', 1, - 'GNU library public license' => 'lgpl', 1, - 'BSD license' => 'bsd', 1, - 'Artistic license' => 'artistic', 1, - 'GPL' => 'gpl', 1, - 'LGPL' => 'lgpl', 1, - 'BSD' => 'bsd', 1, - 'Artistic' => 'artistic', 1, - 'MIT' => 'mit', 1, - 'proprietary' => 'proprietary', 0, - ); - while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { - $pattern =~ s{\s+}{\\s+}g; - if ( $license_text =~ /\b$pattern\b/i ) { - $self->license($license); - return 1; - } + return $self->{values}->{license} unless @_; + my $license = shift or die( + 'Did not provide a value to license()' + ); + $license = __extract_license($license) || lc $license; + $self->{values}->{license} = $license; + + # Automatically fill in license URLs + if ( $license_urls{$license} ) { + $self->resources( license => $license_urls{$license} ); + } + + return 1; +} + +sub _extract_license { + my $pod = shift; + my $matched; + return __extract_license( + ($matched) = $pod =~ m/ + (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) + (=head \d.*|=cut.*|)\z + /xms + ) || __extract_license( + ($matched) = $pod =~ m/ + (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) + (=head \d.*|=cut.*|)\z + /xms + ); +} + +sub __extract_license { + my $license_text = shift or return; + my @phrases = ( + '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, + '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, + 'Artistic and GPL' => 'perl', 1, + 'GNU general public license' => 'gpl', 1, + 'GNU public license' => 'gpl', 1, + 'GNU lesser general public license' => 'lgpl', 1, + 'GNU lesser public license' => 'lgpl', 1, + 'GNU library general public license' => 'lgpl', 1, + 'GNU library public license' => 'lgpl', 1, + 'GNU Free Documentation license' => 'unrestricted', 1, + 'GNU Affero General Public License' => 'open_source', 1, + '(?:Free)?BSD license' => 'bsd', 1, + 'Artistic license' => 'artistic', 1, + 'Apache (?:Software )?license' => 'apache', 1, + 'GPL' => 'gpl', 1, + 'LGPL' => 'lgpl', 1, + 'BSD' => 'bsd', 1, + 'Artistic' => 'artistic', 1, + 'MIT' => 'mit', 1, + 'Mozilla Public License' => 'mozilla', 1, + 'Q Public License' => 'open_source', 1, + 'OpenSSL License' => 'unrestricted', 1, + 'SSLeay License' => 'unrestricted', 1, + 'zlib License' => 'open_source', 1, + 'proprietary' => 'proprietary', 0, + ); + while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { + $pattern =~ s#\s+#\\s+#gs; + if ( $license_text =~ /\b$pattern\b/i ) { + return $license; } } + return ''; +} - warn "Cannot determine license info from $_[0]\n"; - return 'unknown'; +sub license_from { + my $self = shift; + if (my $license=_extract_license(Module::Install::_read($_[0]))) { + $self->license($license); + } else { + warn "Cannot determine license info from $_[0]\n"; + return 'unknown'; + } } sub _extract_bugtracker { - my @links = $_[0] =~ m#L<(\Qhttp://rt.cpan.org/\E[^>]+)>#g; + my @links = $_[0] =~ m#L<( + \Qhttp://rt.cpan.org/\E[^>]+| + \Qhttp://github.com/\E[\w_]+/[\w_]+/issues| + \Qhttp://code.google.com/p/\E[\w_\-]+/issues/list + )>#gx; my %links; @links{@links}=(); @links=keys %links; @@ -485,7 +569,7 @@ sub bugtracker_from { return 0; } if ( @links > 1 ) { - warn "Found more than on rt.cpan.org link in $_[0]\n"; + warn "Found more than one bugtracker link in $_[0]\n"; return 0; } @@ -532,8 +616,15 @@ sub _perl_version { return $v; } - - +sub add_metadata { + my $self = shift; + my %hash = @_; + for my $key (keys %hash) { + warn "add_metadata: $key is not prefixed with 'x_'.\n" . + "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; + $self->{values}->{$key} = $hash{$key}; + } +} ###################################################################### diff --git a/test/inc/Module/Install/Win32.pm b/test/inc/Module/Install/Win32.pm index f2f99df..a9417aa 100644 --- a/test/inc/Module/Install/Win32.pm +++ b/test/inc/Module/Install/Win32.pm @@ -6,7 +6,7 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91'; + $VERSION = '0.99'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } diff --git a/test/inc/Module/Install/WriteAll.pm b/test/inc/Module/Install/WriteAll.pm index 12471e5..75a089f 100644 --- a/test/inc/Module/Install/WriteAll.pm +++ b/test/inc/Module/Install/WriteAll.pm @@ -6,7 +6,7 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '0.91';; + $VERSION = '0.99'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } @@ -26,7 +26,10 @@ sub WriteAll { $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { - $self->makemaker_args( PL_FILES => {} ); + # XXX: This still may be a bit over-defensive... + unless ($self->makemaker(6.25)) { + $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; + } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure diff --git a/test/inc/Test/Builder.pm b/test/inc/Test/Builder.pm index 795361f..14961dc 100644 --- a/test/inc/Test/Builder.pm +++ b/test/inc/Test/Builder.pm @@ -5,7 +5,7 @@ use 5.006; use strict; use warnings; -our $VERSION = '0.94'; +our $VERSION = '0.92'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) BEGIN { @@ -71,7 +71,7 @@ BEGIN { #line 117 -our $Test = Test::Builder->new; +my $Test = Test::Builder->new; sub new { my($class) = shift; @@ -90,127 +90,7 @@ sub create { return $self; } -#line 168 - -sub child { - my( $self, $name ) = @_; - - if( $self->{Child_Name} ) { - $self->croak("You already have a child named ($self->{Child_Name}) running"); - } - - my $child = bless {}, ref $self; - $child->reset; - - # Add to our indentation - $child->_indent( $self->_indent . ' ' ); - $child->{$_} = $self->{$_} foreach qw{Out_FH Todo_FH Fail_FH}; - - # This will be reset in finalize. We do this here lest one child failure - # cause all children to fail. - $child->{Child_Error} = $?; - $? = 0; - $child->{Parent} = $self; - $child->{Name} = $name || "Child of " . $self->name; - $self->{Child_Name} = $child->name; - return $child; -} - - -#line 201 - -sub subtest { - my $self = shift; - my($name, $subtests) = @_; - - if ('CODE' ne ref $subtests) { - $self->croak("subtest()'s second argument must be a code ref"); - } - - # Turn the child into the parent so anyone who has stored a copy of - # the Test::Builder singleton will get the child. - my $child = $self->child($name); - my %parent = %$self; - %$self = %$child; - - my $error; - if( !eval { $subtests->(); 1 } ) { - $error = $@; - } - - # Restore the parent and the copied child. - %$child = %$self; - %$self = %parent; - - # Die *after* we restore the parent. - die $error if $error and !eval { $error->isa('Test::Builder::Exception') }; - - return $child->finalize; -} - - -#line 250 - -sub finalize { - my $self = shift; - - return unless $self->parent; - if( $self->{Child_Name} ) { - $self->croak("Can't call finalize() with child ($self->{Child_Name}) active"); - } - $self->_ending; - - # XXX This will only be necessary for TAP envelopes (we think) - #$self->_print( $self->is_passing ? "PASS\n" : "FAIL\n" ); - - my $ok = 1; - $self->parent->{Child_Name} = undef; - if ( $self->{Skip_All} ) { - $self->parent->skip($self->{Skip_All}); - } - elsif ( not @{ $self->{Test_Results} } ) { - $self->parent->ok( 0, sprintf q[No tests run for subtest "%s"], $self->name ); - } - else { - $self->parent->ok( $self->is_passing, $self->name ); - } - $? = $self->{Child_Error}; - delete $self->{Parent}; - - return $self->is_passing; -} - -sub _indent { - my $self = shift; - - if( @_ ) { - $self->{Indent} = shift; - } - - return $self->{Indent}; -} - -#line 300 - -sub parent { shift->{Parent} } - -#line 312 - -sub name { shift->{Name} } - -sub DESTROY { - my $self = shift; - if ( $self->parent ) { - my $name = $self->name; - $self->diag(<<"FAIL"); -Child ($name) exited without calling finalize() -FAIL - $self->parent->{In_Destroy} = 1; - $self->parent->ok(0, $name); - } -} - -#line 336 +#line 158 our $Level; @@ -221,16 +101,11 @@ sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms) # hash keys is just asking for pain. Also, it was documented. $Level = 1; - $self->{Name} = $0; - $self->is_passing(1); - $self->{Ending} = 0; $self->{Have_Plan} = 0; $self->{No_Plan} = 0; $self->{Have_Output_Plan} = 0; $self->{Original_Pid} = $$; - $self->{Child_Name} = undef; - $self->{Indent} ||= ''; share( $self->{Curr_Test} ); $self->{Curr_Test} = 0; @@ -256,7 +131,7 @@ sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms) return; } -#line 414 +#line 219 my %plan_cmds = ( no_plan => \&no_plan, @@ -304,7 +179,7 @@ sub _plan_tests { } -#line 470 +#line 275 sub expected_tests { my $self = shift; @@ -322,7 +197,7 @@ sub expected_tests { return $self->{Expected_Tests}; } -#line 494 +#line 299 sub no_plan { my($self, $arg) = @_; @@ -336,7 +211,7 @@ sub no_plan { } -#line 528 +#line 333 sub _output_plan { my($self, $max, $directive, $reason) = @_; @@ -354,7 +229,7 @@ sub _output_plan { return; } -#line 579 +#line 384 sub done_testing { my($self, $num_tests) = @_; @@ -387,17 +262,11 @@ sub done_testing { $self->{Have_Plan} = 1; - # The wrong number of tests were run - $self->is_passing(0) if $self->{Expected_Tests} != $self->{Curr_Test}; - - # No tests were run - $self->is_passing(0) if $self->{Curr_Test} == 0; - return 1; } -#line 630 +#line 429 sub has_plan { my $self = shift; @@ -407,21 +276,18 @@ sub has_plan { return(undef); } -#line 647 +#line 446 sub skip_all { my( $self, $reason ) = @_; - $self->{Skip_All} = $self->parent ? $reason : 1; + $self->{Skip_All} = 1; $self->_output_plan(0, "SKIP", $reason) unless $self->no_header; - if ( $self->parent ) { - die bless {} => 'Test::Builder::Exception'; - } exit(0); } -#line 672 +#line 468 sub exported_to { my( $self, $pack ) = @_; @@ -432,16 +298,11 @@ sub exported_to { return $self->{Exported_To}; } -#line 702 +#line 498 sub ok { my( $self, $test, $name ) = @_; - if ( $self->{Child_Name} and not $self->{In_Destroy} ) { - $name = 'unnamed test' unless defined $name; - $self->is_passing(0); - $self->croak("Cannot run test ($name) with active children"); - } # $test might contain an object which we don't want to accidentally # store, so we turn it into a boolean. $test = $test ? 1 : 0; @@ -517,27 +378,9 @@ ERR } } - $self->is_passing(0) unless $test || $self->in_todo; - - # Check that we haven't violated the plan - $self->_check_is_passing_plan(); - return $test ? 1 : 0; } - -# Check that we haven't yet violated the plan and set -# is_passing() accordingly -sub _check_is_passing_plan { - my $self = shift; - - my $plan = $self->has_plan; - return unless defined $plan; # no plan yet defined - return unless $plan !~ /\D/; # no numeric plan - $self->is_passing(0) if $plan < $self->{Curr_Test}; -} - - sub _unoverload { my $self = shift; my $type = shift; @@ -592,7 +435,7 @@ sub _is_dualvar { return $numval != 0 and $numval ne $val ? 1 : 0; } -#line 876 +#line 649 sub is_eq { my( $self, $got, $expect, $name ) = @_; @@ -675,7 +518,7 @@ sub _isnt_diag { DIAGNOSTIC } -#line 973 +#line 746 sub isnt_eq { my( $self, $got, $dont_expect, $name ) = @_; @@ -709,7 +552,7 @@ sub isnt_num { return $self->cmp_ok( $got, '!=', $dont_expect, $name ); } -#line 1022 +#line 797 sub like { my( $self, $this, $regex, $name ) = @_; @@ -725,7 +568,7 @@ sub unlike { return $self->_regex_ok( $this, $regex, '!~', $name ); } -#line 1046 +#line 821 my %numeric_cmps = map { ( $_, 1 ) } ( "<", "<=", ">", ">=", "==", "!=", "<=>" ); @@ -805,7 +648,7 @@ sub _caller_context { return $code; } -#line 1145 +#line 920 sub BAIL_OUT { my( $self, $reason ) = @_; @@ -815,14 +658,11 @@ sub BAIL_OUT { exit 255; } -#line 1158 +#line 933 -{ - no warnings 'once'; - *BAILOUT = \&BAIL_OUT; -} +*BAILOUT = \&BAIL_OUT; -#line 1172 +#line 944 sub skip { my( $self, $why ) = @_; @@ -853,7 +693,7 @@ sub skip { return 1; } -#line 1213 +#line 985 sub todo_skip { my( $self, $why ) = @_; @@ -881,7 +721,7 @@ sub todo_skip { return 1; } -#line 1293 +#line 1062 sub maybe_regex { my( $self, $regex ) = @_; @@ -931,11 +771,15 @@ sub _regex_ok { ## no critic (BuiltinFunctions::ProhibitStringyEval) my $test; - my $context = $self->_caller_context; + my $code = $self->_caller_context; local( $@, $!, $SIG{__DIE__} ); # isolate eval - $test = eval $context . q{$test = $this =~ /$usable_regex/ ? 1 : 0}; + # Yes, it has to look like this or 5.4.5 won't see the #line + # directive. + # Don't ask me, man, I just work here. + $test = eval " +$code" . q{$test = $this =~ /$usable_regex/ ? 1 : 0}; $test = !$test if $cmp eq '!~'; @@ -961,7 +805,7 @@ DIAGNOSTIC # I'm not ready to publish this. It doesn't deal with array return # values from the code or context. -#line 1389 +#line 1162 sub _try { my( $self, $code, %opts ) = @_; @@ -981,7 +825,7 @@ sub _try { return wantarray ? ( $return, $error ) : $return; } -#line 1418 +#line 1191 sub is_fh { my $self = shift; @@ -992,10 +836,11 @@ sub is_fh { return 1 if ref \$maybe_fh eq 'GLOB'; # its a glob return eval { $maybe_fh->isa("IO::Handle") } || - eval { tied($maybe_fh)->can('TIEHANDLE') }; + # 5.5.4's tied() and can() doesn't like getting undef + eval { ( tied($maybe_fh) || '' )->can('TIEHANDLE') }; } -#line 1461 +#line 1235 sub level { my( $self, $level ) = @_; @@ -1006,7 +851,7 @@ sub level { return $Level; } -#line 1493 +#line 1267 sub use_numbers { my( $self, $use_nums ) = @_; @@ -1017,7 +862,7 @@ sub use_numbers { return $self->{Use_Nums}; } -#line 1526 +#line 1300 foreach my $attribute (qw(No_Header No_Ending No_Diag)) { my $method = lc $attribute; @@ -1035,7 +880,7 @@ foreach my $attribute (qw(No_Header No_Ending No_Diag)) { *{ __PACKAGE__ . '::' . $method } = $code; } -#line 1579 +#line 1353 sub diag { my $self = shift; @@ -1043,7 +888,7 @@ sub diag { $self->_print_comment( $self->_diag_fh, @_ ); } -#line 1594 +#line 1368 sub note { my $self = shift; @@ -1080,7 +925,7 @@ sub _print_comment { return 0; } -#line 1644 +#line 1418 sub explain { my $self = shift; @@ -1099,7 +944,7 @@ sub explain { } @_; } -#line 1673 +#line 1447 sub _print { my $self = shift; @@ -1124,10 +969,10 @@ sub _print_to_fh { # Stick a newline on the end if it needs it. $msg .= "\n" unless $msg =~ /\n\z/; - return print $fh $self->_indent, $msg; + return print $fh $msg; } -#line 1732 +#line 1506 sub output { my( $self, $fh ) = @_; @@ -1246,7 +1091,7 @@ sub _copy_io_layers { return; } -#line 1857 +#line 1631 sub reset_outputs { my $self = shift; @@ -1258,7 +1103,7 @@ sub reset_outputs { return; } -#line 1883 +#line 1657 sub _message_at_caller { my $self = shift; @@ -1279,7 +1124,7 @@ sub croak { } -#line 1923 +#line 1697 sub current_test { my( $self, $num ) = @_; @@ -1312,20 +1157,7 @@ sub current_test { return $self->{Curr_Test}; } -#line 1971 - -sub is_passing { - my $self = shift; - - if( @_ ) { - $self->{Is_Passing} = shift; - } - - return $self->{Is_Passing}; -} - - -#line 1993 +#line 1739 sub summary { my($self) = shift; @@ -1333,14 +1165,14 @@ sub summary { return map { $_->{'ok'} } @{ $self->{Test_Results} }; } -#line 2048 +#line 1794 sub details { my $self = shift; return @{ $self->{Test_Results} }; } -#line 2077 +#line 1823 sub todo { my( $self, $pack ) = @_; @@ -1354,7 +1186,7 @@ sub todo { return ''; } -#line 2099 +#line 1845 sub find_TODO { my( $self, $pack ) = @_; @@ -1366,7 +1198,7 @@ sub find_TODO { return ${ $pack . '::TODO' }; } -#line 2117 +#line 1863 sub in_todo { my $self = shift; @@ -1375,7 +1207,7 @@ sub in_todo { return( defined $self->{Todo} || $self->find_TODO ) ? 1 : 0; } -#line 2167 +#line 1913 sub todo_start { my $self = shift; @@ -1390,7 +1222,7 @@ sub todo_start { return; } -#line 2189 +#line 1935 sub todo_end { my $self = shift; @@ -1411,7 +1243,7 @@ sub todo_end { return; } -#line 2222 +#line 1968 sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms) my( $self, $height ) = @_; @@ -1426,9 +1258,9 @@ sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms) return wantarray ? @caller : $caller[0]; } -#line 2239 +#line 1985 -#line 2253 +#line 1999 #'# sub _sanity_check { @@ -1441,7 +1273,7 @@ sub _sanity_check { return; } -#line 2274 +#line 2020 sub _whoa { my( $self, $check, $desc ) = @_; @@ -1456,7 +1288,7 @@ WHOA return; } -#line 2298 +#line 2044 sub _my_exit { $? = $_[0]; ## no critic (Variables::RequireLocalizedPunctuationVars) @@ -1464,12 +1296,10 @@ sub _my_exit { return 1; } -#line 2310 +#line 2056 sub _ending { my $self = shift; - return if $self->no_ending; - return if $self->{Ending}++; my $real_exit_code = $?; @@ -1481,7 +1311,6 @@ sub _ending { # Ran tests but never declared a plan or hit done_testing if( !$self->{Have_Plan} and $self->{Curr_Test} ) { - $self->is_passing(0); $self->diag("Tests were run but no plan was declared and done_testing() was not seen."); } @@ -1493,9 +1322,9 @@ sub _ending { # Don't do an ending if we bailed out. if( $self->{Bailed_Out} ) { - $self->is_passing(0); return; } + # Figure out if we passed or failed and print helpful messages. my $test_results = $self->{Test_Results}; if(@$test_results) { @@ -1523,7 +1352,6 @@ sub _ending { $self->diag(<<"FAIL"); Looks like you planned $self->{Expected_Tests} test$s but ran $self->{Curr_Test}. FAIL - $self->is_passing(0); } if($num_failed) { @@ -1535,14 +1363,13 @@ FAIL $self->diag(<<"FAIL"); Looks like you failed $num_failed test$s of $num_tests$qualifier. FAIL - $self->is_passing(0); } if($real_exit_code) { $self->diag(<<"FAIL"); Looks like your test exited with $real_exit_code just after $self->{Curr_Test}. FAIL - $self->is_passing(0); + _my_exit($real_exit_code) && return; } @@ -1566,24 +1393,21 @@ FAIL $self->diag(<<"FAIL"); Looks like your test exited with $real_exit_code before it could output anything. FAIL - $self->is_passing(0); _my_exit($real_exit_code) && return; } else { $self->diag("No tests run!\n"); - $self->is_passing(0); _my_exit(255) && return; } - $self->is_passing(0); $self->_whoa( 1, "We fell off the end of _ending()" ); } END { - $Test->_ending if defined $Test; + $Test->_ending if defined $Test and !$Test->no_ending; } -#line 2498 +#line 2236 1; diff --git a/test/inc/Test/Builder/Module.pm b/test/inc/Test/Builder/Module.pm index ffef230..de793c1 100644 --- a/test/inc/Test/Builder/Module.pm +++ b/test/inc/Test/Builder/Module.pm @@ -8,11 +8,19 @@ use Test::Builder; require Exporter; our @ISA = qw(Exporter); -our $VERSION = '0.94'; +our $VERSION = '0.92'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) +# 5.004's Exporter doesn't have export_to_level. +my $_export_to_level = sub { + my $pkg = shift; + my $level = shift; + (undef) = shift; # redundant arg + my $callpkg = caller($level); + $pkg->export( $callpkg, @_ ); +}; -#line 74 +#line 82 sub import { my($class) = shift; @@ -31,7 +39,7 @@ sub import { $test->plan(@_); - $class->export_to_level( 1, $class, @imports ); + $class->$_export_to_level( 1, $class, @imports ); } sub _strip_imports { @@ -60,11 +68,11 @@ sub _strip_imports { return @imports; } -#line 137 +#line 145 sub import_extra { } -#line 167 +#line 175 sub builder { return Test::Builder->new; diff --git a/test/inc/Test/More.pm b/test/inc/Test/More.pm index 9d41458..9e98a6a 100644 --- a/test/inc/Test/More.pm +++ b/test/inc/Test/More.pm @@ -18,7 +18,7 @@ sub _carp { return warn @_, " at $file line $line\n"; } -our $VERSION = '0.94'; +our $VERSION = '0.92'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) use Test::Builder::Module; @@ -34,11 +34,10 @@ our @EXPORT = qw(ok use_ok require_ok done_testing can_ok isa_ok new_ok diag note explain - subtest BAIL_OUT ); -#line 164 +#line 163 sub plan { my $tb = Test::More->builder; @@ -72,7 +71,7 @@ sub import_extra { return; } -#line 217 +#line 216 sub done_testing { my $tb = Test::More->builder; @@ -189,7 +188,6 @@ sub isa_ok ($$;$) { } elsif( $error =~ /Can't call method "isa" without a package/ ) { # It's something that can't even be a class - $obj_name = 'The thing' unless defined $obj_name; $diag = "$obj_name isn't a class or reference"; } else { @@ -222,7 +220,7 @@ WHOA return $ok; } -#line 651 +#line 650 sub new_ok { my $tb = Test::More->builder; @@ -247,16 +245,7 @@ sub new_ok { return $obj; } -#line 719 - -sub subtest($&) { - my ($name, $subtests) = @_; - - my $tb = Test::More->builder; - return $tb->subtest(@_); -} - -#line 743 +#line 690 sub pass (;$) { my $tb = Test::More->builder; @@ -270,7 +259,7 @@ sub fail (;$) { return $tb->ok( 0, @_ ); } -#line 806 +#line 753 sub use_ok ($;@) { my( $module, @imports ) = @_; @@ -332,7 +321,7 @@ sub _eval { return( $eval_result, $eval_error ); } -#line 875 +#line 822 sub require_ok ($) { my($module) = shift; @@ -376,7 +365,7 @@ sub _is_module_name { return $module =~ /^[a-zA-Z]\w*$/ ? 1 : 0; } -#line 952 +#line 899 our( @Data_Stack, %Refs_Seen ); my $DNE = bless [], 'Does::Not::Exist'; @@ -483,7 +472,7 @@ sub _type { return ''; } -#line 1112 +#line 1059 sub diag { return Test::More->builder->diag(@_); @@ -493,13 +482,13 @@ sub note { return Test::More->builder->note(@_); } -#line 1138 +#line 1085 sub explain { return Test::More->builder->explain(@_); } -#line 1204 +#line 1151 ## no critic (Subroutines::RequireFinalReturn) sub skip { @@ -527,7 +516,7 @@ sub skip { last SKIP; } -#line 1288 +#line 1238 sub todo_skip { my( $why, $how_many ) = @_; @@ -548,7 +537,7 @@ sub todo_skip { last TODO; } -#line 1343 +#line 1293 sub BAIL_OUT { my $reason = shift; @@ -557,7 +546,7 @@ sub BAIL_OUT { $tb->BAIL_OUT($reason); } -#line 1382 +#line 1332 #'# sub eq_array { @@ -683,7 +672,7 @@ WHOA } } -#line 1515 +#line 1465 sub eq_hash { local @Data_Stack = (); @@ -716,7 +705,7 @@ sub _eq_hash { return $ok; } -#line 1572 +#line 1522 sub eq_set { my( $a1, $a2 ) = @_; @@ -741,6 +730,6 @@ sub eq_set { ); } -#line 1774 +#line 1735 1; diff --git a/test/lib/Test/Nginx.pm b/test/lib/Test/Nginx.pm index 54a2215..2b4fe31 100644 --- a/test/lib/Test/Nginx.pm +++ b/test/lib/Test/Nginx.pm @@ -3,7 +3,7 @@ package Test::Nginx; use strict; use warnings; -our $VERSION = '0.08'; +our $VERSION = '0.10'; __END__ @@ -31,6 +31,76 @@ L All of them are based on L. +=head1 Nginx C modules that use Test::Nginx to drive their test suites + +=over + +=item ngx_echo + +L + +=item ngx_headers_more + +L + +=item ngx_chunkin + +L + +=item ngx_memc + +L + +=item ngx_drizzle + +L + +=item ngx_rds_json + +L + +=item ngx_xss + +L + +=item ngx_srcache + +L + +=item ngx_lua + +L + +=item ngx_set_misc + +L + +=item ngx_array_var + +L + +=item ngx_form_input + +L + +=item ngx_iconv + +L + +=item ngx_set_cconv + +L + +=item ngx_postgres + +L + +=item ngx_coolkit + +L + +=back + =head1 SOURCE REPOSITORY This module has a Git repository on Github, which has access for all. diff --git a/test/lib/Test/Nginx/Echo.pm b/test/lib/Test/Nginx/Echo.pm deleted file mode 100644 index ebe5944..0000000 --- a/test/lib/Test/Nginx/Echo.pm +++ /dev/null @@ -1,520 +0,0 @@ -package Test::Nginx::Echo; - -use lib 'lib'; -use lib 'inc'; -use Test::Base -Base; - -our $NoNginxManager = 0; -our $RepeatEach = 1; - -use Time::HiRes qw(sleep); -use Test::LongString; - -#use Smart::Comments::JSON '##'; -use POSIX qw( SIGQUIT SIGKILL SIGTERM ); -use LWP::UserAgent; # XXX should use a socket level lib here -use Module::Install::Can; -use List::Util qw( shuffle ); -use File::Spec (); -use Cwd qw( cwd ); - -our $UserAgent = LWP::UserAgent->new; -$UserAgent->agent(__PACKAGE__); -#$UserAgent->default_headers(HTTP::Headers->new); - -our $Workers = 1; -our $WorkerConnections = 1024; -our $LogLevel = 'debug'; -#our $MasterProcessEnabled = 'on'; -#our $DaemonEnabled = 'on'; -our $ServerPort = 1984; -our $ServerPortForClient = 1984; -#our $ServerPortForClient = 1984; - -our $NginxVersion; -our $NginxRawVersion; - -#our ($PrevRequest, $PrevConfig); - -our $ServRoot = File::Spec->catfile(cwd(), 't/servroot'); -our $LogDir = File::Spec->catfile($ServRoot, 'logs'); -our $ErrLogFile = File::Spec->catfile($LogDir, 'error.log'); -our $AccLogFile = File::Spec->catfile($LogDir, 'access.log'); -our $HtmlDir = File::Spec->catfile($ServRoot, 'html'); -our $ConfDir = File::Spec->catfile($ServRoot, 'conf'); -our $ConfFile = File::Spec->catfile($ConfDir, 'nginx.conf'); -our $PidFile = File::Spec->catfile($LogDir, 'nginx.pid'); - -our @EXPORT = qw( plan run_tests run_test ); - -=begin cmt - -sub plan (@) { - if (@_ == 2 && $_[0] eq 'tests' && defined $RepeatEach) { - #$_[1] *= $RepeatEach; - } - super; -} - -=end cmt - -=cut - -sub trim ($); - -sub show_all_chars ($); - -sub parse_headers ($); - -sub run_test_helper ($$); - -sub get_canon_version (@) { - sprintf "%d.%03d%03d", $_[0], $_[1], $_[2]; -} - -sub get_nginx_version () { - my $out = `nginx -V 2>&1`; - if (!defined $out || $? != 0) { - warn "Failed to get the version of the Nginx in PATH.\n"; - } - if ($out =~ m{nginx/(\d+)\.(\d+)\.(\d+)}s) { - $NginxRawVersion = "$1.$2.$3"; - return get_canon_version($1, $2, $3); - } - warn "Failed to parse the output of \"nginx -V\": $out\n"; - return undef; -} - -sub run_tests () { - $NginxVersion = get_nginx_version(); - - if (defined $NginxVersion) { - #warn "[INFO] Using nginx version $NginxVersion ($NginxRawVersion)\n"; - } - - for my $block (shuffle blocks()) { - #for (1..3) { - run_test($block); - #} - } -} - -sub setup_server_root () { - if (-d $ServRoot) { - #sleep 0.5; - #die ".pid file $PidFile exists.\n"; - system("rm -rf t/servroot > /dev/null") == 0 or - die "Can't remove t/servroot"; - #sleep 0.5; - } - mkdir $ServRoot or - die "Failed to do mkdir $ServRoot\n"; - mkdir $LogDir or - die "Failed to do mkdir $LogDir\n"; - mkdir $HtmlDir or - die "Failed to do mkdir $HtmlDir\n"; - mkdir $ConfDir or - die "Failed to do mkdir $ConfDir\n"; -} - -sub write_config_file ($) { - my $rconfig = shift; - open my $out, ">$ConfFile" or - die "Can't open $ConfFile for writing: $!\n"; - print $out <<_EOC_; -worker_processes $Workers; -daemon on; -master_process on; -error_log $ErrLogFile $LogLevel; -pid $PidFile; - -http { - access_log $AccLogFile; - - default_type text/plain; - keepalive_timeout 65; - server { - listen $ServerPort; - server_name localhost; - - client_max_body_size 30M; - #client_body_buffer_size 4k; - - # Begin test case config... -$$rconfig - # End test case config. - - location / { - root $HtmlDir; - index index.html index.htm; - } - } -} - -events { - worker_connections $WorkerConnections; -} - -_EOC_ - close $out; -} - -sub parse_request ($$) { - my ($name, $rrequest) = @_; - open my $in, '<', $rrequest; - my $first = <$in>; - if (!$first) { - Test::More::BAIL_OUT("$name - Request line should be non-empty"); - die; - } - $first =~ s/^\s+|\s+$//g; - my ($meth, $rel_url) = split /\s+/, $first, 2; - my $url = "http://localhost:$ServerPortForClient" . $rel_url; - - my $content = do { local $/; <$in> }; - if ($content) { - $content =~ s/^\s+|\s+$//s; - } - - close $in; - - return { - method => $meth, - url => $url, - content => $content, - }; -} - -sub get_pid_from_pidfile ($) { - my ($name) = @_; - open my $in, $PidFile or - Test::More::BAIL_OUT("$name - Failed to open the pid file $PidFile for reading: $!"); - my $pid = do { local $/; <$in> }; - #warn "Pid: $pid\n"; - close $in; - $pid; -} - -sub chunk_it ($$$) { - my ($chunks, $start_delay, $middle_delay) = @_; - my $i = 0; - return sub { - if ($i == 0) { - if ($start_delay) { - sleep($start_delay); - } - } elsif ($middle_delay) { - sleep($middle_delay); - } - return $chunks->[$i++]; - } -} - -sub run_test ($) { - my $block = shift; - my $name = $block->name; - my $request = $block->request; - if (!defined $request) { - #$request = $PrevRequest; - #$PrevRequest = $request; - Test::More::BAIL_OUT("$name - No '--- request' section specified"); - die; - } - - my $config = $block->config; - if (!defined $config) { - Test::More::BAIL_OUT("$name - No '--- config' section specified"); - #$config = $PrevConfig; - die; - } - - my $skip_nginx = $block->skip_nginx; - my ($tests_to_skip, $should_skip, $skip_reason); - if (defined $skip_nginx) { - if ($skip_nginx =~ m{ - ^ \s* (\d+) \s* : \s* - ([<>]=?) \s* (\d+)\.(\d+)\.(\d+) - (?: \s* : \s* (.*) )? - \s*$}x) { - $tests_to_skip = $1; - my ($op, $ver1, $ver2, $ver3) = ($2, $3, $4, $5); - $skip_reason = $6; - #warn "$ver1 $ver2 $ver3"; - my $ver = get_canon_version($ver1, $ver2, $ver3); - if ((!defined $NginxVersion and $op =~ /^todo_nginx; - my ($should_todo, $todo_reason); - if (defined $todo_nginx) { - if ($todo_nginx =~ m{ - ^ \s* - ([<>]=?) \s* (\d+)\.(\d+)\.(\d+) - (?: \s* : \s* (.*) )? - \s*$}x) { - my ($op, $ver1, $ver2, $ver3) = ($1, $2, $3, $4); - $todo_reason = $5; - my $ver = get_canon_version($ver1, $ver2, $ver3); - if ((!defined $NginxVersion and $op =~ /^ /dev/null") == 0) { - write_config_file(\$config); - if (kill(SIGQUIT, $pid) == 0) { # send quit signal - #warn("$name - Failed to send quit signal to the nginx process with PID $pid"); - } - sleep 0.02; - if (system("ps $pid > /dev/null") == 0) { - #warn "killing with force...\n"; - kill(SIGKILL, $pid); - sleep 0.03; - } - undef $nginx_is_running; - } else { - unlink $PidFile or - die "Failed to remove pid file $PidFile\n"; - undef $nginx_is_running; - } - } else { - undef $nginx_is_running; - } - - unless ($nginx_is_running) { - #warn "*** Restarting the nginx server...\n"; - setup_server_root(); - write_config_file(\$config); - if ( ! Module::Install::Can->can_run('nginx') ) { - Test::More::BAIL_OUT("$name - Cannot find the nginx executable in the PATH environment"); - die; - } - #if (system("nginx -p $ServRoot -c $ConfFile -t") != 0) { - #Test::More::BAIL_OUT("$name - Invalid config file"); - #} - #my $cmd = "nginx -p $ServRoot -c $ConfFile > /dev/null"; - my $cmd = "nginx -c $ConfFile > /dev/null"; - if (system($cmd) != 0) { - Test::More::BAIL_OUT("$name - Cannot start nginx using command \"$cmd\"."); - die; - } - sleep 0.1; - } - } - - my $i = 0; - while ($i++ < $RepeatEach) { - if ($should_skip) { - SKIP: { - skip "$name - $skip_reason", $tests_to_skip; - - run_test_helper($block, $request); - } - } elsif ($should_todo) { - TODO: { - local $TODO = "$name - $todo_reason"; - - run_test_helper($block, $request); - } - } else { - run_test_helper($block, $request); - } - } -} - -sub trim ($) { - (my $s = shift) =~ s/^\s+|\s+$//g; - $s =~ s/\n/ /gs; - $s =~ s/\s{2,}/ /gs; - $s; -} - -sub show_all_chars ($) { - my $s = shift; - $s =~ s/\n/\\n/gs; - $s =~ s/\r/\\r/gs; - $s =~ s/\t/\\t/gs; - $s; -} - -sub parse_headers ($) { - my $s = shift; - my %headers; - open my $in, '<', \$s; - while (<$in>) { - s/^\s+|\s+$//g; - my ($key, $val) = split /\s*:\s*/, $_, 2; - $headers{$key} = $val; - } - close $in; - return \%headers; -} - -sub run_test_helper ($$) { - my ($block, $request) = @_; - - my $name = $block->name; - #if (defined $TODO) { - #$name .= "# $TODO"; - #} - - my $req_spec = parse_request($name, \$request); - ## $req_spec - my $method = $req_spec->{method}; - my $req = HTTP::Request->new($method); - my $content = $req_spec->{content}; - - if (defined ($block->request_headers)) { - my $headers = parse_headers($block->request_headers); - while (my ($key, $val) = each %$headers) { - $req->header($key => $val); - } - } - - #$req->header('Accept', '*/*'); - $req->url($req_spec->{url}); - if ($content) { - if ($method eq 'GET' or $method eq 'HEAD') { - croak "HTTP 1.0/1.1 $method request should not have content: $content"; - } - $req->content($content); - } elsif ($method eq 'POST' or $method eq 'PUT') { - my $chunks = $block->chunked_body; - if (defined $chunks) { - if (!ref $chunks or ref $chunks ne 'ARRAY') { - - Test::More::BAIL_OUT("$name - --- chunked_body should takes a Perl array ref as its value"); - } - - my $start_delay = $block->start_chunk_delay || 0; - my $middle_delay = $block->middle_chunk_delay || 0; - $req->content(chunk_it($chunks, $start_delay, $middle_delay)); - if (!defined $req->header('Content-Type')) { - $req->header('Content-Type' => 'text/plain'); - } - } else { - if (!defined $req->header('Content-Type')) { - $req->header('Content-Type' => 'text/plain'); - } - - $req->header('Content-Length' => 0); - } - } - - if ($block->more_headers) { - my @headers = split /\n+/, $block->more_headers; - for my $header (@headers) { - next if $header =~ /^\s*\#/; - my ($key, $val) = split /:\s*/, $header, 2; - #warn "[$key, $val]\n"; - $req->header($key => $val); - } - } - #warn "DONE!!!!!!!!!!!!!!!!!!!!"; - - my $res = $UserAgent->request($req); - - #warn "res returned!!!"; - - if (defined $block->error_code) { - is($res->code, $block->error_code, "$name - status code ok"); - } else { - is($res->code, 200, "$name - status code ok"); - } - - if (defined $block->response_headers) { - my $headers = parse_headers($block->response_headers); - while (my ($key, $val) = each %$headers) { - my $expected_val = $res->header($key); - if (!defined $expected_val) { - $expected_val = ''; - } - is $expected_val, $val, - "$name - header $key ok"; - } - } elsif (defined $block->response_headers_like) { - my $headers = parse_headers($block->response_headers_like); - while (my ($key, $val) = each %$headers) { - my $expected_val = $res->header($key); - if (!defined $expected_val) { - $expected_val = ''; - } - like $expected_val, qr/^$val$/, - "$name - header $key like ok"; - } - } - - if (defined $block->response_body) { - my $content = $res->content; - if (defined $content) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - } - - $content =~ s/^Connection: TE, close\r\n//gms; - my $expected = $block->response_body; - $expected =~ s/\$ServerPort\b/$ServerPort/g; - $expected =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - #warn show_all_chars($content); - - is_string($content, $expected, "$name - response_body - response is expected"); - #is($content, $expected, "$name - response_body - response is expected"); - - } elsif (defined $block->response_body_like) { - my $content = $res->content; - if (defined $content) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - } - $content =~ s/^Connection: TE, close\r\n//gms; - my $expected_pat = $block->response_body_like; - $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; - $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - my $summary = trim($content); - like($content, qr/$expected_pat/s, "$name - response_body_like - response is expected ($summary)"); - } -} - -1; -__END__ - -=head1 NAME - -Test::Nginx::Echo - Test scaffold for the ngx_echo module - -=head1 AUTHOR - -agentzh C<< >> - -=head1 COPYRIGHT & LICENSE - -Copyright (C) 2009 by agentzh. -Copyright (C) 2009 by Taobao Inc. ( http://www.taobao.com ) - -This software is licensed under the terms of the BSD License. - diff --git a/test/lib/Test/Nginx/LWP.pm b/test/lib/Test/Nginx/LWP.pm index 4582d4d..14fc07c 100644 --- a/test/lib/Test/Nginx/LWP.pm +++ b/test/lib/Test/Nginx/LWP.pm @@ -4,7 +4,7 @@ use lib 'lib'; use lib 'inc'; use Test::Base -Base; -our $VERSION = '0.08'; +our $VERSION = '0.10'; our $NoLongString; diff --git a/test/lib/Test/Nginx/Socket.pm b/test/lib/Test/Nginx/Socket.pm index e28ffad..1709937 100644 --- a/test/lib/Test/Nginx/Socket.pm +++ b/test/lib/Test/Nginx/Socket.pm @@ -5,7 +5,7 @@ use lib 'inc'; use Test::Base -Base; -our $VERSION = '0.08'; +our $VERSION = '0.10'; use Encode; use Data::Dumper; @@ -42,6 +42,8 @@ use Test::Nginx::Util qw( log_level no_shuffle no_root_location + server_root + html_dir ); #use Smart::Comments::JSON '###'; @@ -58,7 +60,7 @@ our @EXPORT = qw( plan run_tests run_test master_process_enabled no_long_string workers master_on log_level no_shuffle no_root_location - server_addr + server_addr server_root html_dir ); sub send_request ($$$$); @@ -218,6 +220,13 @@ $parsed_req->{content}"; #warn "raw resonse: [$raw_resp]\n"; + my $raw_headers = ''; + if ($raw_resp =~ /(.*?)\r\n\r\n/s) { + #warn "\$1: $1"; + $raw_headers = $1; + } + #warn "raw headers: $raw_headers\n"; + my $res = HTTP::Response->parse($raw_resp); my $enc = $res->header('Transfer-Encoding'); @@ -275,11 +284,18 @@ $parsed_req->{content}"; if (defined $block->response_headers) { my $headers = parse_headers($block->response_headers); while (my ($key, $val) = each %$headers) { - my $expected_val = $res->header($key); - if (!defined $expected_val) { - $expected_val = ''; + if (!defined $val) { + #warn "HIT"; + unlike $raw_headers, qr/^\s*\Q$key\E\s*:/ms, "$name - header $key not present in the raw headers"; + next; + } + + my $actual_val = $res->header($key); + if (!defined $actual_val) { + $actual_val = ''; } - is $expected_val, $val, + + is $actual_val, $val, "$name - header $key ok"; } } elsif (defined $block->response_headers_like) { @@ -695,6 +711,12 @@ The following sections are supported: =item raw_request +=item user_files + +=item skip_nginx + +=item skip_nginx2 + Both string scalar and string arrays are supported as values. =item raw_request_middle_delay @@ -709,6 +731,10 @@ You'll find live samples in the following Nginx 3rd-party modules: =over +=item ngx_echo + +L + =item ngx_chunkin L @@ -729,6 +755,42 @@ L L +=item ngx_srcache + +L + +=item ngx_lua + +L + +=item ngx_set_misc + +L + +=item ngx_array_var + +L + +=item ngx_form_input + +L + +=item ngx_iconv + +L + +=item ngx_set_cconv + +L + +=item ngx_postgres + +L + +=item ngx_coolkit + +L + =back =head1 SOURCE REPOSITORY diff --git a/test/lib/Test/Nginx/Util.pm b/test/lib/Test/Nginx/Util.pm index 2d63fd2..cd6164a 100644 --- a/test/lib/Test/Nginx/Util.pm +++ b/test/lib/Test/Nginx/Util.pm @@ -3,17 +3,19 @@ package Test::Nginx::Util; use strict; use warnings; -our $VERSION = '0.08'; +our $VERSION = '0.10'; use base 'Exporter'; use POSIX qw( SIGQUIT SIGKILL SIGTERM ); use File::Spec (); use HTTP::Response; -use Module::Install::Can; use Cwd qw( cwd ); use List::Util qw( shuffle ); use Time::HiRes qw( sleep ); +use ExtUtils::MakeMaker (); + +our $LatestNginxVersion = 0.008039; our $NoNginxManager = 0; our $Profiling = 0; @@ -21,7 +23,7 @@ our $Profiling = 0; our $RepeatEach = 1; our $MAX_PROCESSES = 10; -our $NoShuffle = 0; +our $NoShuffle = $ENV{TEST_NGINX_NO_SHUFFLE} || 0; our $UseValgrind = $ENV{TEST_NGINX_USE_VALGRIND}; @@ -39,16 +41,16 @@ if ($Profiling || $UseValgrind) { $ForkManager = new Parallel::ForkManager($MAX_PROCESSES); } +our $NginxBinary = $ENV{TEST_NGINX_BINARY} || 'nginx'; our $Workers = 1; our $WorkerConnections = 64; -our $LogLevel = 'debug'; -our $MasterProcessEnabled = 'off'; +our $LogLevel = $ENV{TEST_NGINX_LOG_LEVEL} || 'debug'; +our $MasterProcessEnabled = $ENV{TEST_NGINX_MASTER_PROCESS} || 'off'; our $DaemonEnabled = 'on'; -our $ServerPort = 1984; -our $ServerPortForClient = $ENV{TEST_NGINX_CLIENT_PORT} || 1984; -our $NoRootLocation = 0; -#our $ServerPortForClient = 1984; - +our $ServerPort = $ENV{TEST_NGINX_SERVER_PORT} || $ENV{TEST_NGINX_PORT} || 1984; +our $ServerPortForClient = $ENV{TEST_NGINX_CLIENT_PORT} || $ENV{TEST_NGINX_PORT} || 1984; +our $NoRootLocation = 0; +our $TestNginxSleep = $ENV{TEST_NGINX_SLEEP} || 0; sub repeat_each (@) { if (@_) { @@ -126,6 +128,8 @@ our @EXPORT_OK = qw( log_level no_shuffle no_root_location + html_dir + server_root ); @@ -148,7 +152,7 @@ our $TODO; #our ($PrevRequest, $PrevConfig); -our $ServRoot = File::Spec->catfile(cwd(), 't/servroot'); +our $ServRoot = $ENV{TEST_NGINX_SERVROOT} || File::Spec->catfile(cwd(), 't/servroot'); our $LogDir = File::Spec->catfile($ServRoot, 'logs'); our $ErrLogFile = File::Spec->catfile($LogDir, 'error.log'); our $AccLogFile = File::Spec->catfile($LogDir, 'access.log'); @@ -157,6 +161,14 @@ our $ConfDir = File::Spec->catfile($ServRoot, 'conf'); our $ConfFile = File::Spec->catfile($ConfDir, 'nginx.conf'); our $PidFile = File::Spec->catfile($LogDir, 'nginx.pid'); +sub html_dir () { + return $HtmlDir; +} + +sub server_root () { + return $ServRoot; +} + sub run_tests () { $NginxVersion = get_nginx_version(); @@ -177,11 +189,18 @@ sub run_tests () { sub setup_server_root () { if (-d $ServRoot) { - #sleep 0.5; - #die ".pid file $PidFile exists.\n"; - system("rm -rf t/servroot > /dev/null") == 0 or - die "Can't remove t/servroot"; - #sleep 0.5; + # Take special care, so we won't accidentally remove + # real user data when TEST_NGINX_SERVROOT is mis-used. + system("rm -rf $ConfDir > /dev/null") == 0 or + die "Can't remove $ConfDir"; + system("rm -rf $HtmlDir > /dev/null") == 0 or + die "Can't remove $HtmlDir"; + system("rm -rf $LogDir > /dev/null") == 0 or + die "Can't remove $LogDir"; + system("rm -rf $ServRoot/*_temp > /dev/null") == 0 or + die "Can't remove $ServRoot/*_temp"; + system("rmdir $ServRoot > /dev/null") == 0 or + die "Can't remove $ServRoot (not empty?)"; } mkdir $ServRoot or die "Failed to do mkdir $ServRoot\n"; @@ -203,8 +222,53 @@ sub setup_server_root () { die "Failed to do mkdir $ConfDir\n"; } -sub write_config_file ($$) { - my ($config, $http_config) = @_; +sub write_user_files ($) { + my $block = shift; + + my $name = $block->name; + + if ($block->user_files) { + my $raw = $block->user_files; + + open my $in, '<', \$raw; + + my @files; + my ($fname, $body); + while (<$in>) { + if (/>>> (\S+)/) { + if ($fname) { + push @files, [$fname, $body]; + } + + $fname = $1; + undef $body; + } else { + $body .= $_; + } + } + + if ($fname) { + push @files, [$fname, $body]; + } + + for my $file (@files) { + my ($fname, $body) = @$file; + #warn "write file $fname with content [$body]\n"; + + if (!defined $body) { + $body = ''; + } + + open my $out, ">$HtmlDir/$fname" or + die "$name - Cannot open $HtmlDir/$fname for writing: $!\n"; + print $out $body; + close $out; + } + } +} + +sub write_config_file ($$$) { + my ($config, $http_config, $main_config) = @_; if (!defined $config) { $config = ''; @@ -214,6 +278,10 @@ sub write_config_file ($$) { $http_config = ''; } + if (!defined $main_config) { + $main_config = ''; + } + open my $out, ">$ConfFile" or die "Can't open $ConfFile for writing: $!\n"; print $out <<_EOC_; @@ -223,6 +291,8 @@ master_process $MasterProcessEnabled; error_log $ErrLogFile $LogLevel; pid $PidFile; +$main_config + http { access_log $AccLogFile; @@ -274,11 +344,11 @@ sub get_canon_version (@) { } sub get_nginx_version () { - my $out = `nginx -V 2>&1`; + my $out = `$NginxBinary -V 2>&1`; if (!defined $out || $? != 0) { warn "Failed to get the version of the Nginx in PATH.\n"; } - if ($out =~ m{nginx/(\d+)\.(\d+)\.(\d+)}s) { + if ($out =~ m{(?:nginx|ngx_openresty)/(\d+)\.(\d+)\.(\d+)}s) { $NginxRawVersion = "$1.$2.$3"; return get_canon_version($1, $2, $3); } @@ -293,7 +363,7 @@ sub get_pid_from_pidfile ($) { my $pid = do { local $/; <$in> }; #warn "Pid: $pid\n"; close $in; - $pid; + return $pid; } sub trim ($) { @@ -317,8 +387,14 @@ sub parse_headers ($) { open my $in, '<', \$s; while (<$in>) { s/^\s+|\s+$//g; - my ($key, $val) = split /\s*:\s*/, $_, 2; - $headers{$key} = $val; + my $neg = ($_ =~ s/^!\s*//); + #warn "neg: $neg ($_)"; + if ($neg) { + $headers{$_} = undef; + } else { + my ($key, $val) = split /\s*:\s*/, $_, 2; + $headers{$key} = $val; + } } close $in; return \%headers; @@ -336,6 +412,7 @@ sub run_test ($) { } my $skip_nginx = $block->skip_nginx; + my $skip_nginx2 = $block->skip_nginx2; my ($tests_to_skip, $should_skip, $skip_reason); if (defined $skip_nginx) { if ($skip_nginx =~ m{ @@ -358,7 +435,37 @@ sub run_test ($) { $skip_nginx); die; } + } elsif (defined $skip_nginx2) { + if ($skip_nginx2 =~ m{ + ^ \s* (\d+) \s* : \s* + ([<>]=?) \s* (\d+)\.(\d+)\.(\d+) + \s* (or|and) \s* + ([<>]=?) \s* (\d+)\.(\d+)\.(\d+) + (?: \s* : \s* (.*) )? + \s*$}x) { + $tests_to_skip = $1; + my ($opa, $ver1a, $ver2a, $ver3a) = ($2, $3, $4, $5); + my $opx = $6; + my ($opb, $ver1b, $ver2b, $ver3b) = ($7, $8, $9, $10); + $skip_reason = $11; + my $vera = get_canon_version($ver1a, $ver2a, $ver3a); + my $verb = get_canon_version($ver1b, $ver2b, $ver3b); + + if ((!defined $NginxVersion) + or (($opx eq "or") and (eval "$NginxVersion $opa $vera" + or eval "$NginxVersion $opb $verb")) + or (($opx eq "and") and (eval "$NginxVersion $opa $vera" + and eval "$NginxVersion $opb $verb"))) + { + $should_skip = 1; + } + } else { + Test::More::BAIL_OUT("$name - Invalid --- skip_nginx2 spec: " . + $skip_nginx2); + die; + } } + if (!defined $skip_reason) { $skip_reason = "various reasons"; } @@ -401,7 +508,7 @@ sub run_test ($) { if (system("ps $pid > /dev/null") == 0) { #warn "found running nginx..."; - write_config_file($config, $block->http_config); + write_config_file($config, $block->http_config, $block->main_config); if (kill(SIGQUIT, $pid) == 0) { # send quit signal #warn("$name - Failed to send quit signal to the nginx process with PID $pid"); } @@ -428,8 +535,9 @@ start_nginx: #warn "*** Restarting the nginx server...\n"; setup_server_root(); - write_config_file($config, $block->http_config); - if ( ! Module::Install::Can->can_run('nginx') ) { + write_user_files($block); + write_config_file($config, $block->http_config, $block->main_config); + if ( ! can_run($NginxBinary) ) { Test::More::BAIL_OUT("$name - Cannot find the nginx executable in the PATH environment"); die; } @@ -437,11 +545,15 @@ start_nginx: #Test::More::BAIL_OUT("$name - Invalid config file"); #} #my $cmd = "nginx -p $ServRoot -c $ConfFile > /dev/null"; + if (!defined $NginxVersion) { + $NginxVersion = $LatestNginxVersion; + } + my $cmd; if ($NginxVersion >= 0.007053) { - $cmd = "nginx -p $ServRoot/ -c $ConfFile > /dev/null"; + $cmd = "$NginxBinary -p $ServRoot/ -c $ConfFile > /dev/null"; } else { - $cmd = "nginx -c $ConfFile > /dev/null"; + $cmd = "$NginxBinary -c $ConfFile > /dev/null"; } if ($UseValgrind) { @@ -475,7 +587,11 @@ start_nginx: } #warn "sleeping"; - sleep 1; + if ($TestNginxSleep) { + sleep $TestNginxSleep; + } else { + sleep 1; + } } else { if (system($cmd) != 0) { Test::More::BAIL_OUT("$name - Cannot start nginx using command \"$cmd\"."); @@ -512,17 +628,33 @@ start_nginx: } } + if (my $total_errlog = $ENV{TEST_NGINX_ERROR_LOG}) { + my $errlog = "$LogDir/error.log"; + if (-s $errlog) { + open my $out, ">>$total_errlog" or + die "Failed to append test case title to $total_errlog: $!\n"; + print $out "\n=== $0 $name\n"; + close $out; + system("cat $errlog >> $total_errlog") == 0 or + die "Failed to append $errlog to $total_errlog. Abort.\n"; + } + } + if ($Profiling || $UseValgrind) { #warn "Found quit..."; if (-f $PidFile) { #warn "found pid file..."; my $pid = get_pid_from_pidfile($name); if (system("ps $pid > /dev/null") == 0) { - write_config_file($config, $block->http_config); + write_config_file($config, $block->http_config, $block->main_config); if (kill(SIGQUIT, $pid) == 0) { # send quit signal warn("$name - Failed to send quit signal to the nginx process with PID $pid"); } - sleep 0.1; + if ($TestNginxSleep) { + sleep $TestNginxSleep; + } else { + sleep 0.1; + } if (-f $PidFile) { #warn "killing with force (valgrind or profile)...\n"; kill(SIGKILL, $pid); @@ -541,14 +673,21 @@ start_nginx: } END { - if ($UseValgrind) { + if ($UseValgrind || !$ENV{TEST_NGINX_NO_CLEAN}) { if (-f $PidFile) { my $pid = get_pid_from_pidfile(''); + if (!$pid) { + die "No pid found."; + } if (system("ps $pid > /dev/null") == 0) { if (kill(SIGQUIT, $pid) == 0) { # send quit signal #warn("$name - Failed to send quit signal to the nginx process with PID $pid"); } - sleep 0.02; + if ($TestNginxSleep) { + sleep $TestNginxSleep; + } else { + sleep 0.02; + } if (system("ps $pid > /dev/null") == 0) { #warn "killing with force...\n"; kill(SIGKILL, $pid); @@ -561,4 +700,20 @@ END { } } +# check if we can run some command +sub can_run { + my ($cmd) = @_; + + my $_cmd = $cmd; + return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); + + for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { + next if $dir eq ''; + my $abs = File::Spec->catfile($dir, $_[1]); + return $abs if (-x $abs or $abs = MM->maybe_command($abs)); + } + + return; +} + 1; From 368bd598bb96ce9ed9a40a48308eeeccf0cbccef Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 26 Aug 2010 11:55:08 +0000 Subject: [PATCH 2/3] Update Test::Nginx. --- test/lib/Test/Nginx/LWP.pm | 66 +++++++++++++++++++------ test/lib/Test/Nginx/Socket.pm | 91 +++++++++++++++++++++++++++-------- test/lib/Test/Nginx/Util.pm | 84 +++++++++++++++++++++++++++----- 3 files changed, 195 insertions(+), 46 deletions(-) diff --git a/test/lib/Test/Nginx/LWP.pm b/test/lib/Test/Nginx/LWP.pm index 14fc07c..7774fa9 100644 --- a/test/lib/Test/Nginx/LWP.pm +++ b/test/lib/Test/Nginx/LWP.pm @@ -51,7 +51,7 @@ sub no_long_string () { $NoLongString = 1; } -sub run_test_helper ($); +sub run_test_helper ($$); $RunTestHelper = \&run_test_helper; @@ -96,8 +96,8 @@ sub chunk_it ($$$) { } } -sub run_test_helper ($) { - my ($block) = @_; +sub run_test_helper ($$) { + my ($block, $dry_run) = @_; my $request = $block->request; @@ -162,14 +162,23 @@ sub run_test_helper ($) { #warn "req: ", $req->as_string, "\n"; #warn "DONE!!!!!!!!!!!!!!!!!!!!"; - my $res = $UserAgent->request($req); + my $res = HTTP::Response->new; + unless ($dry_run) { + $res = $UserAgent->request($req); + } #warn "res returned!!!"; - if (defined $block->error_code) { - is($res->code, $block->error_code, "$name - status code ok"); + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } } else { - is($res->code, 200, "$name - status code ok"); + if (defined $block->error_code) { + is($res->code, $block->error_code, "$name - status code ok"); + } else { + is($res->code, 200, "$name - status code ok"); + } } if (defined $block->response_headers) { @@ -179,8 +188,14 @@ sub run_test_helper ($) { if (!defined $expected_val) { $expected_val = ''; } - is $expected_val, $val, - "$name - header $key ok"; + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } + } else { + is $expected_val, $val, + "$name - header $key ok"; + } } } elsif (defined $block->response_headers_like) { my $headers = parse_headers($block->response_headers_like); @@ -189,8 +204,14 @@ sub run_test_helper ($) { if (!defined $expected_val) { $expected_val = ''; } - like $expected_val, qr/^$val$/, - "$name - header $key like ok"; + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } + } else { + like $expected_val, qr/^$val$/, + "$name - header $key like ok"; + } } } @@ -206,12 +227,18 @@ sub run_test_helper ($) { $expected =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; #warn show_all_chars($content); - if ($NoLongString) { - is($content, $expected, "$name - response_body - response is expected"); + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } } else { - is_string($content, $expected, "$name - response_body - response is expected"); + if ($NoLongString) { + is($content, $expected, "$name - response_body - response is expected"); + } else { + is_string($content, $expected, "$name - response_body - response is expected"); + } + #is($content, $expected, "$name - response_body - response is expected"); } - #is($content, $expected, "$name - response_body - response is expected"); } elsif (defined $block->response_body_like) { my $content = $res->content; @@ -223,7 +250,14 @@ sub run_test_helper ($) { $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; my $summary = trim($content); - like($content, qr/$expected_pat/s, "$name - response_body_like - response is expected ($summary)"); + + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } + } else { + like($content, qr/$expected_pat/s, "$name - response_body_like - response is expected ($summary)"); + } } } diff --git a/test/lib/Test/Nginx/Socket.pm b/test/lib/Test/Nginx/Socket.pm index 1709937..77be09d 100644 --- a/test/lib/Test/Nginx/Socket.pm +++ b/test/lib/Test/Nginx/Socket.pm @@ -15,7 +15,7 @@ use List::MoreUtils qw( any ); use IO::Select (); our $ServerAddr = 'localhost'; -our $Timeout = 2; +our $Timeout = $ENV{TEST_NGINX_TIMEOUT} || 2; use Test::Nginx::Util qw( setup_server_root @@ -44,6 +44,7 @@ use Test::Nginx::Util qw( no_root_location server_root html_dir + server_port ); #use Smart::Comments::JSON '###'; @@ -60,12 +61,13 @@ our @EXPORT = qw( plan run_tests run_test master_process_enabled no_long_string workers master_on log_level no_shuffle no_root_location - server_addr server_root html_dir + server_addr server_root html_dir server_port + timeout ); sub send_request ($$$$); -sub run_test_helper ($); +sub run_test_helper ($$); sub error_event_handler ($); sub read_event_handler ($); @@ -84,6 +86,14 @@ sub server_addr (@) { } } +sub timeout (@) { + if (@_) { + $Timeout = shift; + } else { + $Timeout; + } +} + $RunTestHelper = \&run_test_helper; sub parse_request ($$) { @@ -116,8 +126,8 @@ sub parse_request ($$) { }; } -sub run_test_helper ($) { - my $block = shift; +sub run_test_helper ($$) { + my ($block, $dry_run) = @_; my $name = $block->name; @@ -215,8 +225,14 @@ $parsed_req->{content}"; $timeout = $Timeout; } - my $raw_resp = send_request($req, $block->raw_request_middle_delay, - $timeout, $block->name); + my $raw_resp; + + if ($dry_run) { + $raw_resp = "200 OK HTTP/1.0\r\nContent-Length: 0\r\n\r\n"; + } else { + $raw_resp = send_request($req, $block->raw_request_middle_delay, + $timeout, $block->name); + } #warn "raw resonse: [$raw_resp]\n"; @@ -275,10 +291,16 @@ $parsed_req->{content}"; $res->content($decoded); } - if (defined $block->error_code) { - is($res->code || '', $block->error_code, "$name - status code ok"); + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } } else { - is($res->code || '', 200, "$name - status code ok"); + if (defined $block->error_code) { + is($res->code || '', $block->error_code, "$name - status code ok"); + } else { + is($res->code || '', 200, "$name - status code ok"); + } } if (defined $block->response_headers) { @@ -286,7 +308,13 @@ $parsed_req->{content}"; while (my ($key, $val) = each %$headers) { if (!defined $val) { #warn "HIT"; - unlike $raw_headers, qr/^\s*\Q$key\E\s*:/ms, "$name - header $key not present in the raw headers"; + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } + } else { + unlike $raw_headers, qr/^\s*\Q$key\E\s*:/ms, "$name - header $key not present in the raw headers"; + } next; } @@ -295,8 +323,14 @@ $parsed_req->{content}"; $actual_val = ''; } - is $actual_val, $val, - "$name - header $key ok"; + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } + } else { + is $actual_val, $val, + "$name - header $key ok"; + } } } elsif (defined $block->response_headers_like) { my $headers = parse_headers($block->response_headers_like); @@ -305,8 +339,14 @@ $parsed_req->{content}"; if (!defined $expected_val) { $expected_val = ''; } - like $expected_val, qr/^$val$/, - "$name - header $key like ok"; + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } + } else { + like $expected_val, qr/^$val$/, + "$name - header $key like ok"; + } } } @@ -337,10 +377,16 @@ $parsed_req->{content}"; #warn show_all_chars($content); #warn "no long string: $NoLongString"; - if ($NoLongString) { - is($content, $expected, "$name - response_body - response is expected"); + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } } else { - is_string($content, $expected, "$name - response_body - response is expected"); + if ($NoLongString) { + is($content, $expected, "$name - response_body - response is expected"); + } else { + is_string($content, $expected, "$name - response_body - response is expected"); + } } } elsif (defined $block->response_body_like) { @@ -353,7 +399,14 @@ $parsed_req->{content}"; $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; my $summary = trim($content); - like($content, qr/$expected_pat/s, "$name - response_body_like - response is expected ($summary)"); + + if ($dry_run) { + SKIP: { + Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); + } + } else { + like($content, qr/$expected_pat/s, "$name - response_body_like - response is expected ($summary)"); + } } } diff --git a/test/lib/Test/Nginx/Util.pm b/test/lib/Test/Nginx/Util.pm index cd6164a..3d220cf 100644 --- a/test/lib/Test/Nginx/Util.pm +++ b/test/lib/Test/Nginx/Util.pm @@ -52,6 +52,14 @@ our $ServerPortForClient = $ENV{TEST_NGINX_CLIENT_PORT} || $ENV{TEST_NGINX_PO our $NoRootLocation = 0; our $TestNginxSleep = $ENV{TEST_NGINX_SLEEP} || 0; +sub server_port (@) { + if (@_) { + $ServerPort = shift; + } else { + $ServerPort; + } +} + sub repeat_each (@) { if (@_) { $RepeatEach = shift; @@ -130,6 +138,7 @@ our @EXPORT_OK = qw( no_root_location html_dir server_root + server_port ); @@ -169,6 +178,10 @@ sub server_root () { return $ServRoot; } +sub bail_out ($) { + Test::More::BAIL_OUT(@_); +} + sub run_tests () { $NginxVersion = get_nginx_version(); @@ -270,6 +283,8 @@ sub write_user_files ($) { sub write_config_file ($$$) { my ($config, $http_config, $main_config) = @_; + $http_config = expand_env_in_config($http_config); + if (!defined $config) { $config = ''; } @@ -359,7 +374,7 @@ sub get_nginx_version () { sub get_pid_from_pidfile ($) { my ($name) = @_; open my $in, $PidFile or - Test::More::BAIL_OUT("$name - Failed to open the pid file $PidFile for reading: $!"); + bail_out("$name - Failed to open the pid file $PidFile for reading: $!"); my $pid = do { local $/; <$in> }; #warn "Pid: $pid\n"; close $in; @@ -400,13 +415,53 @@ sub parse_headers ($) { return \%headers; } +sub expand_env_in_config ($) { + my $config = shift; + + if (!defined $config) { + return; + } + + $config =~ s/\$(TEST_NGINX_[_A-Z]+)/ + if (!defined $ENV{$1}) { + bail_out "No environment $1 defined.\n"; + } + $ENV{$1}/eg; + + $config; +} + +sub check_if_missing_directives () { + open my $in, $ErrLogFile or + bail_out "check_if_missing_directives: Cannot open $ErrLogFile for reading: $!\n"; + + while (<$in>) { + #warn $_; + if (/\[emerg\] \S+?: unknown directive "([^"]+)"/) { + #warn "MATCHED!!! $1"; + return $1; + } + } + + close $in; + + #warn "NOT MATCHED!!!"; + + return 0; +} + sub run_test ($) { my $block = shift; my $name = $block->name; my $config = $block->config; + + $config = expand_env_in_config($config); + + my $dry_run = 0; + if (!defined $config) { - Test::More::BAIL_OUT("$name - No '--- config' section specified"); + bail_out("$name - No '--- config' section specified"); #$config = $PrevConfig; die; } @@ -431,7 +486,7 @@ sub run_test ($) { $should_skip = 1; } } else { - Test::More::BAIL_OUT("$name - Invalid --- skip_nginx spec: " . + bail_out("$name - Invalid --- skip_nginx spec: " . $skip_nginx); die; } @@ -460,7 +515,7 @@ sub run_test ($) { $should_skip = 1; } } else { - Test::More::BAIL_OUT("$name - Invalid --- skip_nginx2 spec: " . + bail_out("$name - Invalid --- skip_nginx2 spec: " . $skip_nginx2); die; } @@ -487,7 +542,7 @@ sub run_test ($) { $should_todo = 1; } } else { - Test::More::BAIL_OUT("$name - Invalid --- todo_nginx spec: " . + bail_out("$name - Invalid --- todo_nginx spec: " . $todo_nginx); die; } @@ -538,7 +593,7 @@ start_nginx: write_user_files($block); write_config_file($config, $block->http_config, $block->main_config); if ( ! can_run($NginxBinary) ) { - Test::More::BAIL_OUT("$name - Cannot find the nginx executable in the PATH environment"); + bail_out("$name - Cannot find the nginx executable in the PATH environment"); die; } #if (system("nginx -p $ServRoot -c $ConfFile -t") != 0) { @@ -594,7 +649,14 @@ start_nginx: } } else { if (system($cmd) != 0) { - Test::More::BAIL_OUT("$name - Cannot start nginx using command \"$cmd\"."); + if ($ENV{TEST_NGINX_IGNORE_MISSING_DIRECTIVES} and + my $directive = check_if_missing_directives()) + { + $dry_run = $directive; + + } else { + bail_out("$name - Cannot start nginx using command \"$cmd\"."); + } } } @@ -605,7 +667,7 @@ start_nginx: if ($block->init) { eval $block->init; if ($@) { - Test::More::BAIL_OUT("$name - init failed: $@"); + bail_out("$name - init failed: $@"); } } @@ -615,16 +677,16 @@ start_nginx: SKIP: { Test::More::skip("$name - $skip_reason", $tests_to_skip); - $RunTestHelper->($block); + $RunTestHelper->($block, $dry_run); } } elsif ($should_todo) { TODO: { local $TODO = "$name - $todo_reason"; - $RunTestHelper->($block); + $RunTestHelper->($block, $dry_run); } } else { - $RunTestHelper->($block); + $RunTestHelper->($block, $dry_run); } } From 5592b7175815bd09719214a5383086ede80f64b9 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 26 Aug 2010 12:07:00 +0000 Subject: [PATCH 3/3] Use $TEST_NGINX_MEMCACHED_PORT instead of hardcoded value. --- test/t/memc.t | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/t/memc.t b/test/t/memc.t index 70c06cf..e1e4c3f 100644 --- a/test/t/memc.t +++ b/test/t/memc.t @@ -5,6 +5,8 @@ use Test::Nginx::Socket; # skip_all => 'ngx_memc storage commands do not work wi plan tests => repeat_each() * 2 * blocks(); +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + no_long_string(); #no_diff; @@ -15,7 +17,7 @@ __DATA__ === TEST 1: set in eval (NO subrequest in memory) --- http_config upstream mc { - server localhost:11984; + server 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; } --- config @@ -49,7 +51,7 @@ __DATA__ === TEST 2: set in eval (subrequest in memory) --- http_config upstream mc { - server localhost:11984; + server 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; } --- config