Blame testing/RUNFULLTESTS

Packit Service b38f0b
#!/usr/bin/env perl
Packit Service b38f0b
Packit Service b38f0b
use Getopt::Long;
Packit Service b38f0b
#use Data::Dumper;
Packit Service b38f0b
use File::Basename;
Packit Service b38f0b
use File::Spec;
Packit Service b38f0b
use Cwd qw(abs_path);
Packit Service b38f0b
use strict;
Packit Service b38f0b
Packit Service b38f0b
########################################
Packit Service b38f0b
# Globals and Command Line options
Packit Service b38f0b
Packit Service b38f0b
my %opts = ('groups' => 'default',
Packit Service b38f0b
            'master-directory' => 'fulltests',
Packit Service b38f0b
	    'srcdir' => dirname("$0") . "/..",
Packit Service b38f0b
            'builddir' => '..',
Packit Service b38f0b
	    'failed-file' => 'failed_tests',
Packit Service b38f0b
	   );
Packit Service b38f0b
Packit Service b38f0b
Getopt::Long::Configure(qw(no_ignore_case));
Packit Service b38f0b
GetOptions(\%opts,
Packit Service b38f0b
           "verbose",
Packit Service b38f0b
           "help|?",
Packit Service b38f0b
           "quiet|q",
Packit Service b38f0b
           "groups|g=s",
Packit Service b38f0b
           "r=s",
Packit Service b38f0b
           "debug",
Packit Service b38f0b
           "srcdir|D=s",
Packit Service b38f0b
           "builddir|d=s",
Packit Service b38f0b
	   "f",
Packit Service b38f0b
	   "F",
Packit Service b38f0b
	   "failed-file=s",
Packit Service b38f0b
	   "master-directory=s",
Packit Service b38f0b
	  ) || ++$opts{'help'};
Packit Service b38f0b
Packit Service b38f0b
# Change srcdir and builddir to absolute paths
Packit Service b38f0b
$opts{'srcdir'} = abs_path($opts{'srcdir'});
Packit Service b38f0b
$opts{'builddir'} = abs_path($opts{'builddir'});
Packit Service b38f0b
# Set exeext.
Packit Service b38f0b
$opts{'exeext'} = join(readpipe($opts{'builddir'} . '/net-snmp-config --exeext'));
Packit Service b38f0b
Packit Service b38f0b
usage() if ($opts{'help'});
Packit Service b38f0b
Packit Service b38f0b
# Build the harness object
Packit Service b38f0b
my %args = (
Packit Service b38f0b
	    verbosity => ($opts{'verbose'} ? 1 : ($opts{'quiet'} ? -1 : 0)),
Packit Service b38f0b
	    exec => \&decide_exec,
Packit Service b38f0b
	    # this option is *really* weird in how it works
Packit Service b38f0b
	    failures => ($opts{'quiet'} ? 0 : ($opts{'verbose'} ? 0 : 1)),
Packit Service b38f0b
	    errors => ($opts{'quiet'} ? 0 : 1),
Packit Service b38f0b
	   );
Packit Service b38f0b
Packit Service b38f0b
# list of support infrastructure components
Packit Service b38f0b
my %support;
Packit Service b38f0b
my %sources;
Packit Service b38f0b
Packit Service b38f0b
# if the -d option was specified, pass on the source root directory to all apps
Packit Service b38f0b
if (exists($opts{'master-directory'})) {
Packit Service b38f0b
    $ENV{'NETSNMPSRCDIR'} = $opts{'master-directory'};
Packit Service b38f0b
} else {
Packit Service b38f0b
    $ENV{'NETSNMPSRCDIR'} = '.';
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
# pass srcdir and builddir to all apps
Packit Service b38f0b
$ENV{'srcdir'} = $opts{'srcdir'};
Packit Service b38f0b
$ENV{'builddir'} = $opts{'builddir'};
Packit Service b38f0b
Packit Service b38f0b
# set up MIBDIRS to refer to the src directory
Packit Service b38f0b
if (!$ENV{'MIBDIRS'}) {
Packit Service b38f0b
    $ENV{'MIBDIRS'} = "$opts{srcdir}/mibs";
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
my $cfp_path = File::Spec->catfile(dirname(abs_path($0)), "check_for_pskill");
Packit Service b38f0b
my $rc = `$cfp_path`;
Packit Service b38f0b
if ($rc != 0) {
Packit Service b38f0b
    die "$cfp_path failed with error code $rc\n";
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
########################################
Packit Service b38f0b
# Protection measures
Packit Service b38f0b
$ENV{'SNMPCONFPATH'} = "/dev/null";
Packit Service b38f0b
Packit Service b38f0b
# create the testing harness infrastructure
Packit Service b38f0b
Packit Service b38f0b
my $harness;
Packit Service b38f0b
if (eval { require TAP::Harness; } ) {
Packit Service b38f0b
    import TAP::Harness;
Packit Service b38f0b
    $harness = TAP::Harness->new(\%args);
Packit Service b38f0b
} else {
Packit Service b38f0b
    require Test::Harness;
Packit Service b38f0b
    import Test::Harness;
Packit Service b38f0b
    if ($opts{'groups'} ne 'default') {
Packit Service b38f0b
	print STDERR "
Packit Service b38f0b
ERROR: I can not find the perl TAP::Harness module.  We support the
Packit Service b38f0b
more common Test::Harness module but only for the default test group.
Packit Service b38f0b
Packit Service b38f0b
Either:
Packit Service b38f0b
  1) run only the default tests (i.e., just \"make test\")
Packit Service b38f0b
  2) install the TAP::Harness perl module
Packit Service b38f0b
Packit Service b38f0b
";
Packit Service b38f0b
	exit 1;
Packit Service b38f0b
    }
Packit Service b38f0b
    DIE("Test::Harness must be of version 1.21 or newer\n" .
Packit Service b38f0b
	"Install the TAP::Harness module or use the RUNTESTS script\n")
Packit Service b38f0b
      if $Test::Harness::VERSION < 1.21;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
Packit Service b38f0b
########################################
Packit Service b38f0b
# gather the tests
Packit Service b38f0b
my @tests;
Packit Service b38f0b
Packit Service b38f0b
DEBUG("Gathering and building tests:\n");
Packit Service b38f0b
find_support();
Packit Service b38f0b
if ($opts{'f'}) {
Packit Service b38f0b
    DIE("The -f and -g options can not be both specified\n")
Packit Service b38f0b
      if ($opts{'groups'} ne 'default');
Packit Service b38f0b
    DIE("The -f and -r options can not be both specified\n") if ($opts{'r'});
Packit Service b38f0b
    DIE("No $opts{'failed-file'} file was found to read failed state from\n")
Packit Service b38f0b
      if (! -f $opts{'failed-file'});
Packit Service b38f0b
    open(F, $opts{'failed-file'});
Packit Service b38f0b
    while (<F>) {
Packit Service b38f0b
	chomp;
Packit Service b38f0b
	push @tests, build_test($_);
Packit Service b38f0b
    }
Packit Service b38f0b
} else {
Packit Service b38f0b
    @tests = gather_tests($opts{'groups'}, $opts{'r'});
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
########################################
Packit Service b38f0b
# rename them to remove parent dirs
Packit Service b38f0b
@tests = rename_tests(@tests);
Packit Service b38f0b
Packit Service b38f0b
########################################
Packit Service b38f0b
# run the tests
Packit Service b38f0b
Packit Service b38f0b
DEBUG("Running tests:\n"); 
Packit Service b38f0b
DEBUG("-" x 78, "\n");
Packit Service b38f0b
Packit Service b38f0b
my $results;
Packit Service b38f0b
if ($harness) {
Packit Service b38f0b
    $results = $harness->runtests(@tests);
Packit Service b38f0b
} else {
Packit Service b38f0b
    # minimal backwards compat with Test::Harness
Packit Service b38f0b
    run_older_perl_tests(@tests);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
my @failed = $results->failed();
Packit Service b38f0b
if (!$opts{'q'} && $#failed > -1) {
Packit Service b38f0b
    print "\nWe failed these ", (1 + $#failed), " tests:\n";
Packit Service b38f0b
    my @lines = @failed;
Packit Service b38f0b
    map { if (exists($sources{$_})) { $_ = "$_ ( $sources{$_} )"} } @lines;
Packit Service b38f0b
    print "  ", join("\n  ",@lines), "\n";
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
if (!$opts{'F'}) {
Packit Service b38f0b
    open(F,">$opts{'failed-file'}");
Packit Service b38f0b
    if ($#failed > -1) {
Packit Service b38f0b
	print F join("\n", get_sources(@failed)) . "\n";
Packit Service b38f0b
    }
Packit Service b38f0b
    close(F);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
exit($results->all_passed() ? 0 : 1);
Packit Service b38f0b
Packit Service b38f0b
######################################################################
Packit Service b38f0b
# Infrastructure
Packit Service b38f0b
#
Packit Service b38f0b
Packit Service b38f0b
########################################
Packit Service b38f0b
# decides how we should execute a test
Packit Service b38f0b
#
Packit Service b38f0b
sub decide_exec {
Packit Service b38f0b
    my ( $harness, $testfile ) = @_;
Packit Service b38f0b
Packit Service b38f0b
    # 1) Parse the $testfile argument.
Packit Service b38f0b
    my ($dirname, $groupname, $basename, $app_extension, $file_extension) = 
Packit Service b38f0b
      ($testfile =~ /([^\/]+)\/([^\/]+)\/([^\/]+)_([^\/_]+)\.*([^\/\.]*)$/);
Packit Service b38f0b
    $app_extension =~ s/$opts{'exeext'}\$//;
Packit Service b38f0b
Packit Service b38f0b
    # 2) we have a RUN_TYPE file in the same directory
Packit Service b38f0b
    if (exists($support{'run'}{$app_extension}{$groupname})) {
Packit Service b38f0b
	return [$support{'run'}{$app_extension}{$groupname}, $testfile];
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    # 3) return a generic run script
Packit Service b38f0b
    if (exists($support{'run'}{$app_extension}{'generic'})) {
Packit Service b38f0b
	return [$support{'run'}{$app_extension}{'generic'}, $testfile];
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    # 4) give up and let the test harness decide itself
Packit Service b38f0b
    return undef;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub gather_tests {
Packit Service b38f0b
    my ( $groups, $regexp ) = @_;
Packit Service b38f0b
    my @groups;
Packit Service b38f0b
Packit Service b38f0b
    # figure out the list of groups we need to search through
Packit Service b38f0b
    if ($groups eq 'all') {
Packit Service b38f0b
	# find every group we can
Packit Service b38f0b
	# we exclude:
Packit Service b38f0b
	#  - things not a directory
Packit Service b38f0b
	#  - anything with "template" in the name
Packit Service b38f0b
	@groups =
Packit Service b38f0b
	  grep { !/(template|support)/ &&
Packit Service b38f0b
		   -d $_ && s/$opts{'srcdir'}\/testing\/$opts{'master-directory'}.// } glob("$opts{'srcdir'}/testing/$opts{'master-directory'}/*");
Packit Service b38f0b
    } else {
Packit Service b38f0b
	# they specified a comma separated list
Packit Service b38f0b
	@groups = split(/,\s*/, $groups);
Packit Service b38f0b
    }
Packit Service b38f0b
    DEBUG("Checking groups: ", join(", ", @groups), "\n");
Packit Service b38f0b
Packit Service b38f0b
    my @tests;
Packit Service b38f0b
    foreach my $group (@groups) {
Packit Service b38f0b
	my @files;
Packit Service b38f0b
Packit Service b38f0b
	DEBUG("checking group $group\n");
Packit Service b38f0b
Packit Service b38f0b
	if (! -d "$opts{'srcdir'}/testing/$opts{'master-directory'}/$group") {
Packit Service b38f0b
	    ERROR("group '$group' is not a directory under '$opts{'srcdir'}/testing/$opts{'master-directory'}'; ignoring\n");
Packit Service b38f0b
	    next;
Packit Service b38f0b
	}
Packit Service b38f0b
Packit Service b38f0b
	# push on all files that start with T[NUM]*
Packit Service b38f0b
	push_or_skip(\@tests, $regexp, glob("$opts{'srcdir'}/testing/$opts{'master-directory'}/$group/T[0-9]*"));
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    return @tests;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub push_or_skip {
Packit Service b38f0b
    my ($array, $regexp, @files) = @_;
Packit Service b38f0b
    foreach my $file (@files) {
Packit Service b38f0b
	next if ($file =~ /.(bak|old|orig|rej)$/);
Packit Service b38f0b
	next if ($file =~ /~$/);
Packit Service b38f0b
	next if (defined($regexp) && $file !~ /$regexp/i);
Packit Service b38f0b
	DEBUG("  Adding file $file\n");
Packit Service b38f0b
	push @$array, build_test($file);
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
# rename all the tests to remove the top subdir to help readability
Packit Service b38f0b
sub rename_tests {
Packit Service b38f0b
    my (@tests) = @_;
Packit Service b38f0b
    my @newtests;
Packit Service b38f0b
Packit Service b38f0b
    # yes, I could have used map.  But I didn't.
Packit Service b38f0b
    foreach my $file (@tests) {
Packit Service b38f0b
	my $title = "$file";
Packit Service b38f0b
	my $foundheader = 0;
Packit Service b38f0b
	$title = $sources{$file} if (exists($sources{$file}));
Packit Service b38f0b
	
Packit Service b38f0b
	open(SRC, $title);
Packit Service b38f0b
	while (<SRC>) {
Packit Service b38f0b
	    if (/(HEADER|TITLE)\s+['"]*(.*)/) {
Packit Service b38f0b
		$title = $2;
Packit Service b38f0b
		$title =~ s/\s*\*\/.*//;
Packit Service b38f0b
		$title =~ s/['"]$//;
Packit Service b38f0b
		$foundheader = 1;
Packit Service b38f0b
		last;
Packit Service b38f0b
	    }
Packit Service b38f0b
	}
Packit Service b38f0b
	close(SRC);
Packit Service b38f0b
Packit Service b38f0b
	if (! $foundheader) {
Packit Service b38f0b
	    $title =~ s/^$opts{'srcdir'}\/testing\///;
Packit Service b38f0b
	    $title =~ s/$opts{'master-directory'}.//;
Packit Service b38f0b
	}
Packit Service b38f0b
	$sources{$title} = $sources{$file} || $file;
Packit Service b38f0b
	push @newtests, [$file, $title];
Packit Service b38f0b
    }
Packit Service b38f0b
    return @newtests;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
# called to possibly manipulate the list of tests to run by building some
Packit Service b38f0b
sub build_tests {
Packit Service b38f0b
    my (@tests) = @_;
Packit Service b38f0b
    my @newtests;
Packit Service b38f0b
Packit Service b38f0b
    foreach my $test (@tests) {
Packit Service b38f0b
	my $title;
Packit Service b38f0b
	
Packit Service b38f0b
	my $built = build_test($test);
Packit Service b38f0b
	if (ref($built) eq 'ARRAY') {
Packit Service b38f0b
	    push @newtests, @$built;
Packit Service b38f0b
	} elsif ($built ne "") {
Packit Service b38f0b
	    push @newtests, $built;
Packit Service b38f0b
	}
Packit Service b38f0b
    }
Packit Service b38f0b
    return @newtests;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
#
Packit Service b38f0b
# Finds scripts that are used to build and run actual commands
Packit Service b38f0b
#
Packit Service b38f0b
sub find_builders {
Packit Service b38f0b
    $support{'build'} = {};
Packit Service b38f0b
    find_scripts('build', $support{'build'});
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub find_runners {
Packit Service b38f0b
    $support{'run'} = {};
Packit Service b38f0b
    find_scripts('run', $support{'run'});
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub find_support {
Packit Service b38f0b
    find_builders();
Packit Service b38f0b
    find_runners();
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub find_scripts {
Packit Service b38f0b
    my ($buildname, $hashref) = @_;
Packit Service b38f0b
    my $count;
Packit Service b38f0b
    DEBUG("looking for $buildname scripts\n");
Packit Service b38f0b
    foreach my $builder (glob("$opts{'srcdir'}/testing/$opts{'master-directory'}/*/*_${buildname}")) {
Packit Service b38f0b
	next if ($builder =~ /~$/);
Packit Service b38f0b
	next if ($builder =~ /.(bak|orig|rej|old)$/);
Packit Service b38f0b
Packit Service b38f0b
	my ($group, $type) = ($builder =~ /([^\/]+)\/([^\/]*)_${buildname}/);
Packit Service b38f0b
	# save this as a certain group builder
Packit Service b38f0b
	$hashref->{$type}{$group} = $builder;
Packit Service b38f0b
Packit Service b38f0b
	# save this as a generic builder if there isn't a better
Packit Service b38f0b
	# generic one, such as one that exists in the support
Packit Service b38f0b
	# directory.
Packit Service b38f0b
	if (!exists($hashref->{$type}{'generic'}) || $group eq 'support') {
Packit Service b38f0b
	    $hashref->{$type}{'generic'} = $builder;
Packit Service b38f0b
	}
Packit Service b38f0b
	$count++;
Packit Service b38f0b
    }
Packit Service b38f0b
    DEBUG("  found $count\n");
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
# called to build a test from a registerd builder
Packit Service b38f0b
sub build_test {
Packit Service b38f0b
    my ($testfile) = @_;
Packit Service b38f0b
Packit Service b38f0b
    my ($dirname, $groupname, $basename, $app_extension, $file_extension) = 
Packit Service b38f0b
      ($testfile =~ /([^\/]+)\/([^\/]+)\/([^\/]+)_([^\/_]+)\.([^\/\.]+)$/);
Packit Service b38f0b
Packit Service b38f0b
    # is this even a buildable type recipe?
Packit Service b38f0b
    if (!$dirname || !$basename || !$app_extension || !$file_extension) {
Packit Service b38f0b
	return $testfile;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    DEBUG("found: $testfile => $dirname, $basename, $app_extension, $file_extension\n");
Packit Service b38f0b
Packit Service b38f0b
    # choices:
Packit Service b38f0b
    # 1) we have a registered subroutine to build an extension from
Packit Service b38f0b
    # XXX
Packit Service b38f0b
Packit Service b38f0b
    # 2) we have a BUILD_TYPE file in the same directory
Packit Service b38f0b
    if (exists($support{'build'}{$app_extension}{$dirname})) {
Packit Service b38f0b
	return
Packit Service b38f0b
	  call_build_script($support{'build'}{$app_extension}{$dirname}, $testfile);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    # 3) return a generic build script
Packit Service b38f0b
    if (exists($support{'build'}{$app_extension}{'generic'})) {
Packit Service b38f0b
	return
Packit Service b38f0b
	  call_build_script($support{'build'}{$app_extension}{'generic'}, $testfile);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    # 4) we assume it's fine as is
Packit Service b38f0b
    return $testfile;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub call_build_script {
Packit Service b38f0b
    my ($scriptname, $filename) = @_;
Packit Service b38f0b
Packit Service b38f0b
    my $maybenewfile = $filename;
Packit Service b38f0b
    $maybenewfile =~ s/.[^\.]+$/$opts{'exeext'}/;
Packit Service b38f0b
    $maybenewfile =~ s/T([^\/]+)$/B$1/;  # change prefix to B for 'Built'
Packit Service b38f0b
    $maybenewfile =~ s/^$opts{'srcdir'}\///;
Packit Service b38f0b
Packit Service b38f0b
    my $newpath = $maybenewfile;
Packit Service b38f0b
    $newpath =~ s/\/[^\/]*$//;
Packit Service b38f0b
Packit Service b38f0b
    if (! -d $newpath) {
Packit Service b38f0b
	DEBUG("making directory $newpath\n");
Packit Service b38f0b
	system("$opts{'srcdir'}/mkinstalldirs $newpath");
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    my $lastline;
Packit Service b38f0b
    DEBUG("BUILDING: $scriptname $filename $maybenewfile\n");
Packit Service b38f0b
    open(B,"$scriptname $filename $maybenewfile|");
Packit Service b38f0b
    while () {
Packit Service b38f0b
	$lastline = $_;
Packit Service b38f0b
    }
Packit Service b38f0b
    chomp($lastline);
Packit Service b38f0b
Packit Service b38f0b
    DEBUG("  result: $lastline\n");
Packit Service b38f0b
    return undef if ($lastline eq 'fail');
Packit Service b38f0b
    return undef if ($lastline eq 'skip');
Packit Service b38f0b
    return $filename if ($lastline eq '');
Packit Service b38f0b
    $sources{$lastline} = $filename;        # remember where we came from
Packit Service b38f0b
    return $lastline;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub get_sources {
Packit Service b38f0b
    my (@names) = @_;
Packit Service b38f0b
    map { if (exists($sources{$_})) { $_ = $sources{$_} } } @names;
Packit Service b38f0b
    return @names;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub run_older_perl_tests {
Packit Service b38f0b
    #
Packit Service b38f0b
    # Older versions of perl used a different test suite called Test::Harness
Packit Service b38f0b
    # It is much more limited than TAP::Harness;
Packit Service b38f0b
    #
Packit Service b38f0b
    # Here we massage our older tests into something that will work under
Packit Service b38f0b
    # Test::Harness too.
Packit Service b38f0b
    #
Packit Service b38f0b
    my @tests = @_;
Packit Service b38f0b
Packit Service b38f0b
    # create the temporary files
Packit Service b38f0b
    my @tempfiles;
Packit Service b38f0b
    if (! -d "$opts{'master-directory'}") {
Packit Service b38f0b
	mkdir("$opts{'master-directory'}", 0777);
Packit Service b38f0b
    }
Packit Service b38f0b
    if (! -d "$opts{'master-directory'}/temptests") {
Packit Service b38f0b
	mkdir("$opts{'master-directory'}/temptests", 0777);
Packit Service b38f0b
    }
Packit Service b38f0b
    foreach my $test (@tests) {
Packit Service b38f0b
	my $tempfile = "$test->[0].t";
Packit Service b38f0b
	$tempfile =~ s#^$opts{'srcdir'}#$opts{'builddir'}#;
Packit Service b38f0b
	$tempfile =~ s#$opts{'master-directory'}/default/#$opts{'master-directory'}/temptests/#;
Packit Service b38f0b
	open(T, ">$tempfile") || die("$tempfile: $!");
Packit Service b38f0b
	print T "# functionally perl\n\nsystem(\"$opts{'srcdir'}/testing/fulltests/support/simple_run $test->[0]\");\n";
Packit Service b38f0b
	close(T);
Packit Service b38f0b
	chmod(0755, $tempfile);
Packit Service b38f0b
	push @tempfiles, $tempfile;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    $results = runtests(@tempfiles);
Packit Service b38f0b
Packit Service b38f0b
    unlink(@tempfiles) || die("$@ $!");
Packit Service b38f0b
    exit;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
# usage output
Packit Service b38f0b
sub usage {
Packit Service b38f0b
    print "$0 [OPTIONS]\n";
Packit Service b38f0b
Packit Service b38f0b
    print "\nOPTIONS:\n";
Packit Service b38f0b
    print "  -v\t\t\tRuns in verbose mode; dumping all test output\n";
Packit Service b38f0b
    print "    --verbose\n";
Packit Service b38f0b
    print "  -q\t\t\tRuns in quieter mode; dumps less test output\n";
Packit Service b38f0b
    print "    --quiet\n";
Packit Service b38f0b
    print "  -g GROUP\t\tRuns the group of specified tests (default = 'default')\n";
Packit Service b38f0b
    print "    --group GROUP\n";
Packit Service b38f0b
    print "\t\t\t(use 'all' to run all tests)\n";
Packit Service b38f0b
    print "  -r REGEXP\t\tOnly run test files matching this regexp\n";
Packit Service b38f0b
    print "  -f\t\t\tRun only the failed tests from the last run\n";
Packit Service b38f0b
    print "  -F\t\t\tDon't create the failed_tests file\n";
Packit Service b38f0b
    print "  --failed-file FILE\tThe location of the failed state file\n";
Packit Service b38f0b
    print "  -D PATH\t\tSource directory\n";
Packit Service b38f0b
    print "    --srcdir PATH\n";
Packit Service b38f0b
    print "    (currently '$opts{'srcdir'}')\n";
Packit Service b38f0b
    print "  -d PATH\t\tBuild directory to be tested\n";
Packit Service b38f0b
    print "    --builddir PATH\n";
Packit Service b38f0b
    print "    (currently '$opts{'builddir'}')\n";
Packit Service b38f0b
    print "  --master-directory DIRNAME\n";
Packit Service b38f0b
    print "    (default = 'fulltests')\n";
Packit Service b38f0b
    print "  -h\t\t\tThis help output\n";
Packit Service b38f0b
    print "    --help\n";
Packit Service b38f0b
    print "  --debug\t\tDebugging output\n\n";
Packit Service b38f0b
    exit;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub DEBUG {
Packit Service b38f0b
    return if (!$opts{'debug'});
Packit Service b38f0b
    print @_;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub ERROR {
Packit Service b38f0b
    print STDERR "Error:", @_;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
sub DIE {
Packit Service b38f0b
    ERROR(@_);
Packit Service b38f0b
    exit 1;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
=pod
Packit Service b38f0b
Packit Service b38f0b
=head1 NAME
Packit Service b38f0b
Packit Service b38f0b
runfulltests - the Net-SNMP test suite coordinator
Packit Service b38f0b
Packit Service b38f0b
=head1 SYNOPSIS
Packit Service b38f0b
Packit Service b38f0b
runfulltests [OPTIONS]
Packit Service b38f0b
Packit Service b38f0b
# ./RUNFULLTESTS
Packit Service b38f0b
Packit Service b38f0b
# ./RUNFULLTESTS -g all
Packit Service b38f0b
Packit Service b38f0b
=head1 DESCRIPTION
Packit Service b38f0b
Packit Service b38f0b
B<RUNFULLTESTS> is a TAP (see below) output aggregator and test suite
Packit Service b38f0b
management program.  It runs groups of tests that it can find in the
Packit Service b38f0b
I<fulltests> sub-directory.  It defaults to running a basic set of
Packit Service b38f0b
high-level Net-SNMP tests found in the fulltests/default directory.
Packit Service b38f0b
To run a different set of tests see the -g flag.
Packit Service b38f0b
Packit Service b38f0b
It is able to keep state and remember which tests failed so that
Packit Service b38f0b
during development you can simply re-run only the "last failed tests"
Packit Service b38f0b
using the -f switch.
Packit Service b38f0b
Packit Service b38f0b
=head2 Perl Requirements
Packit Service b38f0b
Packit Service b38f0b
Ideally it should be run under a fairly modern version of perl (eg,
Packit Service b38f0b
5.10) but minmial support is provided for older versions of perl as
Packit Service b38f0b
well.
Packit Service b38f0b
Packit Service b38f0b
If no perl is available on the system, there is also a fall-back
Packit Service b38f0b
"RUNTESTS" suite which merely executes the default scripts for testing
Packit Service b38f0b
compliance of the high-level applications.
Packit Service b38f0b
Packit Service b38f0b
=head2 Important Notes About Writing New Tests
Packit Service b38f0b
Packit Service b38f0b
When designing new tests it is strongly encouraged that some
Packit Service b38f0b
conventions are followed:
Packit Service b38f0b
Packit Service b38f0b
  - Design the test files so they can be build/run without them
Packit Service b38f0b
    needing to be build/run within a testing harness like this one
Packit Service b38f0b
    (B<RUNFULLTESTS>).  IE, you should be able to run them directly by
Packit Service b38f0b
    hand for debugging purposes without requiring them to be invoked
Packit Service b38f0b
    within this or any other testing harness.
Packit Service b38f0b
  - Name them beginning with TNNN where NNN is a 3 digit number
Packit Service b38f0b
Packit Service b38f0b
The rational behind these rules follows in the sections below
Packit Service b38f0b
Packit Service b38f0b
=head1 OPTIONS
Packit Service b38f0b
Packit Service b38f0b
=over
Packit Service b38f0b
Packit Service b38f0b
=item -g GROUP
Packit Service b38f0b
Packit Service b38f0b
=item --group GROUP
Packit Service b38f0b
Packit Service b38f0b
By default the "default" group of tests is run.  Which is really just
Packit Service b38f0b
everything that B<RUNFULLTESTS> can find from the I<fulltests/default>
Packit Service b38f0b
sub-directory.  The -g switch can be used to specify other
Packit Service b38f0b
sub-directories of tests to run.  The argument is a comma-separated
Packit Service b38f0b
list of subdirectories to use.
Packit Service b38f0b
Packit Service b38f0b
The special keyword I<all> can be used to run every test in every
Packit Service b38f0b
subdirectory of the I<fulltests> directory.
Packit Service b38f0b
Packit Service b38f0b
=item -r REGEXP
Packit Service b38f0b
Packit Service b38f0b
Only run test files that match the I<REGEXP> regular expression.
Packit Service b38f0b
Packit Service b38f0b
To run only tests of a certain file name you might combine this with
Packit Service b38f0b
'-g all'.  E.G., -g all -r snmpv3 will run all snmpv3 (named) tests
Packit Service b38f0b
that B<RUNFULLTESTS> can find.
Packit Service b38f0b
Packit Service b38f0b
=item -f
Packit Service b38f0b
Packit Service b38f0b
Only run the tests that failed from the last run.
Packit Service b38f0b
Packit Service b38f0b
=item --failed-file FILE
Packit Service b38f0b
Packit Service b38f0b
Where to store the state of which tests have failed.
Packit Service b38f0b
Packit Service b38f0b
=item -F
Packit Service b38f0b
Packit Service b38f0b
Don't save state to the failed-file.
Packit Service b38f0b
Packit Service b38f0b
=item -D PATH
Packit Service b38f0b
Packit Service b38f0b
=item --srcdir PATH
Packit Service b38f0b
Packit Service b38f0b
If RUNFULLTESTS is being executed from a build directory other than
Packit Service b38f0b
where the source files are located, this flag can be used to specify
Packit Service b38f0b
where the Net-SNMP root source directory is found.
Packit Service b38f0b
Packit Service b38f0b
=item -d PATH
Packit Service b38f0b
Packit Service b38f0b
=item --builddir PATH
Packit Service b38f0b
Packit Service b38f0b
Specifies the root of the build directory.
Packit Service b38f0b
Packit Service b38f0b
=item --master-directory DIRNAME
Packit Service b38f0b
Packit Service b38f0b
Specifies an alternate master directory.  The default is "fulltests"
Packit Service b38f0b
Packit Service b38f0b
=item -v
Packit Service b38f0b
Packit Service b38f0b
=item --verbose
Packit Service b38f0b
Packit Service b38f0b
Turns on verbose output mode.
Packit Service b38f0b
Packit Service b38f0b
=item -q
Packit Service b38f0b
Packit Service b38f0b
=item --quiet
Packit Service b38f0b
Packit Service b38f0b
Turns on quiet output mode.
Packit Service b38f0b
Packit Service b38f0b
=item --debug
Packit Service b38f0b
Packit Service b38f0b
Turns on debugging output (which primarily shows how B<RUNFULLTESTS>
Packit Service b38f0b
is collecting tests to run, etc).
Packit Service b38f0b
Packit Service b38f0b
=item -h
Packit Service b38f0b
Packit Service b38f0b
=item --help
Packit Service b38f0b
Packit Service b38f0b
Command line usage help output.
Packit Service b38f0b
Packit Service b38f0b
=back
Packit Service b38f0b
Packit Service b38f0b
=head1 TEST ARCHITECTURE
Packit Service b38f0b
Packit Service b38f0b
=head2 TAP output
Packit Service b38f0b
Packit Service b38f0b
TAP stands for "Test Anything Protocol".  TAP was originally
Packit Service b38f0b
perl-specific but has been turning out to be a generic protocol for
Packit Service b38f0b
testing just about anything.  It's heavily documented at:
Packit Service b38f0b
Packit Service b38f0b
  http://testanything.org/wiki/index.php/Main_Page
Packit Service b38f0b
Packit Service b38f0b
We're using TAP because it's highly flexible and separates the
Packit Service b38f0b
invidual tests from the "collect and report" aspect.  RUNFULLTESTS is
Packit Service b38f0b
simply a perl-based implementation for collecting and summarizing the
Packit Service b38f0b
test results.  Other collection agents could be used instead of this
Packit Service b38f0b
one, and any sort of test or language could be used for the individual
Packit Service b38f0b
tests as well (in fact the default suite has some that are SH-based,
Packit Service b38f0b
C-based, ...).
Packit Service b38f0b
Packit Service b38f0b
It may be that eventually the TAP protocol actually makes it into the
Packit Service b38f0b
IETF (http://testanything.org/wiki/index.php/TAP_at_IETF:_Draft_Standard).
Packit Service b38f0b
Packit Service b38f0b
The syntax of TAP is very simple.  See the above web page for a
Packit Service b38f0b
complete description, but this will provide you a minimal "getting
Packit Service b38f0b
started" example and shows the output of 5 sub-tests run from a single
Packit Service b38f0b
test application.
Packit Service b38f0b
Packit Service b38f0b
  1..5
Packit Service b38f0b
  ok 1 - Yay
Packit Service b38f0b
  ok 2 - Second part succeeded
Packit Service b38f0b
  not ok 3 - Oh no...  A problem occurred.
Packit Service b38f0b
  not ok 4 - The computer thought 2+2 was 5
Packit Service b38f0b
  ok 5 - All is well that ends well
Packit Service b38f0b
Packit Service b38f0b
That's it.  Output from a test tool like that is auto-summarized by
Packit Service b38f0b
this application in success/fail reports.
Packit Service b38f0b
Packit Service b38f0b
=head2 Testing Phases
Packit Service b38f0b
Packit Service b38f0b
The testing process goes through the following phases:
Packit Service b38f0b
Packit Service b38f0b
 - Test and Infrastructure Collection
Packit Service b38f0b
 - Test Execution
Packit Service b38f0b
   - Build if needed
Packit Service b38f0b
   - Run
Packit Service b38f0b
Packit Service b38f0b
=head2 Test Collection
Packit Service b38f0b
Packit Service b38f0b
B<RUNFULLTESTS> will search all the requested groups for files that
Packit Service b38f0b
begin with the letter 'T'.  They are executed in alphabetical order
Packit Service b38f0b
within their group.  Convention is to number test files with a three
Packit Service b38f0b
digit (zero-padded) number after the 'T' letter to ensure ordering is
Packit Service b38f0b
as expected.
Packit Service b38f0b
Packit Service b38f0b
Files to be collected by B<RUNFULLTESTS> are made up of a number of
Packit Service b38f0b
components to support a flexible build and execution system (discussed
Packit Service b38f0b
in detail in the following sections).  They are structured as follows:
Packit Service b38f0b
Packit Service b38f0b
  T<NNN><NAME>_<TYPE>.<SUFFIX>
Packit Service b38f0b
Packit Service b38f0b
Where:
Packit Service b38f0b
Packit Service b38f0b
  NNN:      Is the 3 digit number mentioned above.
Packit Service b38f0b
  NAME:     The filename of the test describing what it's about
Packit Service b38f0b
  TYPE:     The internal "type" of the test, which is used later in building
Packit Service b38f0b
            and execution (see below).
Packit Service b38f0b
  .SUFFIX:  An optional file-type suffix
Packit Service b38f0b
Packit Service b38f0b
Examples:
Packit Service b38f0b
Packit Service b38f0b
  fulltests/default/T001snmpv1get_simple
Packit Service b38f0b
  fulltests/snmpv3/T040keymanagetest_capp.c
Packit Service b38f0b
Packit Service b38f0b
Any other files are ignored in terms of tests and may be supplimental
Packit Service b38f0b
to the above build systems.  (Supporting files, by convention, begin
Packit Service b38f0b
with a capital 'S').
Packit Service b38f0b
Packit Service b38f0b
=head3 Full Title
Packit Service b38f0b
Packit Service b38f0b
Within the file there may be a line containing "HEADER ..." that will
Packit Service b38f0b
be examined for a better title of the test.  Anything before "HEADER"
Packit Service b38f0b
will be ignored, and the special "*/" will be replaced as well.  For
Packit Service b38f0b
example, these are valid header source lines:
Packit Service b38f0b
Packit Service b38f0b
  # HEADER A cool test
Packit Service b38f0b
  /* HEADER A cool test from my C-based source file */
Packit Service b38f0b
Packit Service b38f0b
=head2 Infrastructure Collection
Packit Service b38f0b
Packit Service b38f0b
In addition to test files, I<infrastructure> files are searched for
Packit Service b38f0b
and remembered for later use (again, see below).  These files will be
Packit Service b38f0b
of the form:
Packit Service b38f0b
Packit Service b38f0b
  <TYPE>_<USEAGE>
Packit Service b38f0b
Packit Service b38f0b
Where:
Packit Service b38f0b
Packit Service b38f0b
  TYPE:      The type name matching the file to support.
Packit Service b38f0b
Packit Service b38f0b
  USAGE:     How this file should be used.  Currently should be either
Packit Service b38f0b
            I<build> or I<run> as described below.
Packit Service b38f0b
Packit Service b38f0b
Example files
Packit Service b38f0b
Packit Service b38f0b
  fulltests/support/clib_build
Packit Service b38f0b
  fulltests/support/simple_run
Packit Service b38f0b
Packit Service b38f0b
Infrastructure files may exist in the source directory of where they're
Packit Service b38f0b
expected to be run (ie, parallel to the test files) or they may exist
Packit Service b38f0b
in the special "support" directory if they're expected to be
Packit Service b38f0b
generically used across multilpe test group types.
Packit Service b38f0b
Packit Service b38f0b
=head2 Test Execution
Packit Service b38f0b
Packit Service b38f0b
Tests are run in two phases using the following pseudo-algorithm:
Packit Service b38f0b
Packit Service b38f0b
  + for each test file
Packit Service b38f0b
    + if an appropriate TYPE_build file exists for a test {
Packit Service b38f0b
      + run "TYPE_build TESTFILE"
Packit Service b38f0b
      + record the last line as the new TESTFILE to run
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    + if an apporpriate TYPE_run file exists for a test {
Packit Service b38f0b
      + run "TYPE_run TESTFILE"
Packit Service b38f0b
      + collect it's output as the TAP output
Packit Service b38f0b
    } else {
Packit Service b38f0b
      + run "TESTFILE"
Packit Service b38f0b
      + collect it's output as the TAP output
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
For example, if the following files existed:
Packit Service b38f0b
Packit Service b38f0b
  fulltests/examplres/T001testing_examp
Packit Service b38f0b
  fulltests/examplres/examp_build
Packit Service b38f0b
  fulltests/examplres/examp_run
Packit Service b38f0b
Packit Service b38f0b
Then the following would be the rough execution:
Packit Service b38f0b
Packit Service b38f0b
  newfile = `fulltests/examplres/examp_build \
Packit Service b38f0b
             fulltests/examplres/T001testing_examp | tail -1`
Packit Service b38f0b
  fulltests/examplres/examp_run $newfile
Packit Service b38f0b
Packit Service b38f0b
=head1 TEST TYPES
Packit Service b38f0b
Packit Service b38f0b
Net-SNMP testing comes with a number of test suite "builders" and
Packit Service b38f0b
"runners" that are useful for developing new tests.  These are
Packit Service b38f0b
documented here:
Packit Service b38f0b
Packit Service b38f0b
=over
Packit Service b38f0b
Packit Service b38f0b
=item simple
Packit Service b38f0b
Packit Service b38f0b
I<simple> test files are simple sh-shell-script files used to test
Packit Service b38f0b
high-level functionality of Net-SNMP tools.  They're easy to write and
Packit Service b38f0b
should generally contain the following sort of structure:
Packit Service b38f0b
Packit Service b38f0b
  . ../support/simple_eval_tools.sh
Packit Service b38f0b
  HEADER my name
Packit Service b38f0b
  STARTAGENT
Packit Service b38f0b
  CAPTURE "snmpget..."
Packit Service b38f0b
  CHECK "for this string"
Packit Service b38f0b
  STOPAGENT
Packit Service b38f0b
  FINISHED
Packit Service b38f0b
Packit Service b38f0b
Example file: fulltests/default/T001snmpv1get_simple
Packit Service b38f0b
Packit Service b38f0b
=item capp
Packit Service b38f0b
Packit Service b38f0b
I<capp> files are fundamentally full C-source-code applications that
Packit Service b38f0b
are built and linked against the libnetsnmp library.  Thus, a file
Packit Service b38f0b
named I<T001mytest_capp.c> is compiled using the same compiler used to
Packit Service b38f0b
compile Net-SNMP and linked against the required libraries for a basic
Packit Service b38f0b
Net-SNMP application.  It should, of course, produce TAP output after
Packit Service b38f0b
it's compiled and run.
Packit Service b38f0b
Packit Service b38f0b
Example file: fulltests/snmpv3/T010scapitest_capp.c
Packit Service b38f0b
Packit Service b38f0b
=item clib
Packit Service b38f0b
Packit Service b38f0b
I<clib> files are simple C-source-code files that are wrapped into a
Packit Service b38f0b
main() application with appropriate #include files, etc.  I<clib>
Packit Service b38f0b
files are designed primarly to write quick unit-tests for the Net-SNMP
Packit Service b38f0b
core library.
Packit Service b38f0b
Packit Service b38f0b
Example file: fulltests/unit-tests/T001defaultstore_clib.c
Packit Service b38f0b
Packit Service b38f0b
=item Write your own!
Packit Service b38f0b
Packit Service b38f0b
This test system is designed to be flexible and expandable if the
Packit Service b38f0b
basic architecture is followed.  The goal is to make it easy to create
Packit Service b38f0b
very simple test suites or complex unit-tests or anything in between.
Packit Service b38f0b
Packit Service b38f0b
=back
Packit Service b38f0b
Packit Service b38f0b
=head1 DEBUGGING BROKEN TESTS
Packit Service b38f0b
Packit Service b38f0b
If the individual tests are designed well, you should be able to
Packit Service b38f0b
re-run individual tests outside of the B<RUNFULLTESTS> aggregation
Packit Service b38f0b
environment using the appropriate _build and _run scripts as needed.
Packit Service b38f0b
Test writers are encouraged to output comments in their TAP output to
Packit Service b38f0b
help users debug the results.
Packit Service b38f0b
Packit Service b38f0b
=head1 Author
Packit Service b38f0b
Packit Service b38f0b
Original architecture: Wes Hardaker <hardaker@users.sourceforge.net>
Packit Service b38f0b
Packit Service b38f0b
=cut
Packit Service b38f0b