Override KRB5CCNAME so existing Kerberos tickets in the users environment don't get...
[ira/wip.git] / source / selftest / selftest.pl
index 370120ab6388b59abd753b622291dae7410d72fe..aab2ca8f07f0422ccb8f45f653cd797b25bb80b3 100755 (executable)
@@ -13,7 +13,7 @@ selftest - Samba test runner
 
 selftest --help
 
-selftest [--srcdir=DIR] [--builddir=DIR] [--target=samba4|samba3|win] [--socket-wrapper] [--quick] [--one] [--prefix=prefix] [--immediate] [TESTS]
+selftest [--srcdir=DIR] [--builddir=DIR] [--target=samba4|samba3|win] [--socket-wrapper] [--quick] [--exclude=FILE] [--include=FILE] [--one] [--prefix=prefix] [--immediate] [--testlist=FILE] [TESTS]
 
 =head1 DESCRIPTION
 
@@ -67,17 +67,32 @@ these tests will be counted as successes, successes will be counted as failures.
 
 The format for the file is, one entry per line:
 
-TESTSUITE-NAME/TEST-NAME
+TESTSUITE-NAME.TEST-NAME
 
-=item I<--skip>
+The reason for a test can also be specified, by adding a hash sign (#) and the reason 
+after the test name.
 
-Specify a file containing a list of tests that should be skipped. Possible candidates are
-tests that segfault the server, flip or don't end.
+=item I<--exclude>
+
+Specify a file containing a list of tests that should be skipped. Possible 
+candidates are tests that segfault the server, flip or don't end. The format of this file is the same as 
+for the --expected-failures flag.
+
+=item I<--include>
+
+Specify a file containing a list of tests that should be run. Same format 
+as the --exclude flag.
+
+Not includes specified means all tests will be run.
 
 =item I<--one>
 
 Abort as soon as one test fails.
 
+=item I<--testlist>
+
+Load a list of tests from the specified location.
+
 =back
 
 =head1 ENVIRONMENT
@@ -115,9 +130,6 @@ use POSIX;
 use Cwd qw(abs_path);
 use lib "$RealBin";
 use Subunit qw(parse_results);
-use env::Samba3;
-use env::Samba4;
-use env::Windows;
 use SocketWrapper;
 
 my $opt_help = 0;
@@ -129,7 +141,8 @@ my $opt_socket_wrapper_keep_pcap = undef;
 my $opt_one = 0;
 my $opt_immediate = 0;
 my $opt_expected_failures = undef;
-my $opt_skip = undef;
+my @opt_exclude = ();
+my @opt_include = ();
 my $opt_verbose = 0;
 my $opt_testenv = 0;
 my $ldap = undef;
@@ -138,20 +151,18 @@ my $opt_resetup_env = undef;
 my $opt_bindir = undef;
 my $opt_no_lazy_setup = undef;
 my $opt_format = "plain";
+my @testlists = ();
 
 my $srcdir = ".";
 my $builddir = ".";
 my $prefix = "./st";
 
 my @expected_failures = ();
-my @skips = ();
+my @includes = ();
+my @excludes = ();
 
 my $statistics = {
-       START_TIME => time(),
-
        SUITES_FAIL => 0,
-       SUITES_OK => 0,
-       SUITES_SKIPPED => 0,
 
        TESTS_UNEXPECTED_OK => 0,
        TESTS_EXPECTED_OK => 0,
@@ -161,96 +172,100 @@ my $statistics = {
        TESTS_SKIP => 0,
 };
 
-sub expecting_failure($)
+sub find_in_list($$)
 {
-       my $fullname = shift;
+       my ($list, $fullname) = @_;
 
-       foreach (@expected_failures) {
-               return 1 if ($fullname =~ /$_/);
+       foreach (@$list) {
+               if ($fullname =~ /$$_[0]/) {
+                        return ($$_[1]) if ($$_[1]);
+                        return "NO REASON SPECIFIED";
+               }
        }
 
-       return 0;
+       return undef;
 }
 
-sub skip($)
+sub expecting_failure($)
 {
-       my $fullname = shift;
+       my ($name) = @_;
+       return find_in_list(\@expected_failures, $name);
+}
 
-       foreach (@skips) {
-               return 1 if ($fullname =~ /$_/);
-       }
+sub skip($)
+{
+       my ($name) = @_;
 
-       return 0;
+       return find_in_list(\@excludes, $name);
 }
 
 sub getlog_env($);
 
 sub setup_pcap($)
 {
-       my ($state) = @_;
+       my ($state, $name) = @_;
 
        return unless ($opt_socket_wrapper_pcap);
        return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
 
-       my $fname = sprintf("t%03u_%s", $state->{INDEX}, $state->{NAME});
+       my $fname = $name;
        $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
 
-       $state->{PCAP_FILE} = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
+       my $pcap_file = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
 
-       SocketWrapper::setup_pcap($state->{PCAP_FILE});
+       SocketWrapper::setup_pcap($pcap_file);
+
+       return $pcap_file;
 }
 
 sub cleanup_pcap($$$)
 {
-       my ($state, $expected_ret, $ret) = @_;
+       my ($pcap_file, $expected_ret, $ret) = @_;
 
        return unless ($opt_socket_wrapper_pcap);
        return if ($opt_socket_wrapper_keep_pcap);
        return unless ($expected_ret == $ret);
-       return unless defined($state->{PCAP_FILE});
+       return unless defined($pcap_file);
 
-       unlink($state->{PCAP_FILE});
-       $state->{PCAP_FILE} = undef;
+       unlink($pcap_file);
 }
 
 sub run_testsuite($$$$$$)
 {
        my ($envname, $name, $cmd, $i, $totalsuites, $msg_ops) = @_;
-       my $msg_state = {
-               ENVNAME => $envname,
-               NAME    => $name,
-               CMD     => $cmd,
-               INDEX   => $i,
-               TOTAL   => $totalsuites,
-               START_TIME      => time()
-       };
+       my $pcap_file = setup_pcap($name);
 
-       setup_pcap($msg_state);
+       $msg_ops->start_test([], $name);
 
        open(RESULT, "$cmd 2>&1|");
-       $msg_ops->start_testsuite($msg_state);
-
        my $expected_ret = parse_results(
-               $msg_ops, $msg_state, $statistics, *RESULT, \&expecting_failure);
+               $msg_ops, $statistics, *RESULT, \&expecting_failure, [$name]);
+
+       my $envlog = getlog_env($envname);
+       $msg_ops->output_msg("ENVLOG: $envlog\n") if ($envlog ne "");
+
+       $msg_ops->output_msg("CMD: $cmd\n");
 
        my $ret = close(RESULT);
+       $ret = 0 unless $ret == 1;
 
-       cleanup_pcap($msg_state, $expected_ret, $ret);
+       if ($ret == 1) {
+               $msg_ops->end_test([], $name, "success", $expected_ret != $ret, undef);
+       } else {
+               $msg_ops->end_test([], $name, "failure", $expected_ret != $ret, 
+                                              "Returned $ret");
+       }
 
-       $msg_ops->end_testsuite($msg_state, $expected_ret, $ret,
-                                                       getlog_env($msg_state->{ENVNAME}));
+       cleanup_pcap($pcap_file, $expected_ret, $ret);
 
        if (not $opt_socket_wrapper_keep_pcap and 
-               defined($msg_state->{PCAP_FILE})) {
-               $msg_ops->output_msg($msg_state, 
-                       "PCAP FILE: $msg_state->{PCAP_FILE}\n");
+               defined($pcap_file)) {
+               $msg_ops->output_msg("PCAP FILE: $pcap_file\n");
        }
 
        if ($ret != $expected_ret) {
                $statistics->{SUITES_FAIL}++;
                exit(1) if ($opt_one);
-       } else {
-               $statistics->{SUITES_OK}++;
        }
 
        return ($ret == $expected_ret);
@@ -266,6 +281,7 @@ Usage: $Script [OPTIONS] PREFIX
 Generic options:
  --help                     this help page
  --target=samba4|samba3|win Samba version to target
+ --testlist=FILE                       file to read available tests from
 
 Paths:
  --prefix=DIR               prefix to run tests in [st]
@@ -273,7 +289,7 @@ Paths:
  --builddir=DIR             output directory [.]
 
 Target Specific:
- --socket-wrapper-pcap=DIR     save traffic to pcap directories
+ --socket-wrapper-pcap         save traffic to pcap directories
  --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that 
                             failed
  --socket-wrapper           enable socket wrapper
@@ -306,7 +322,8 @@ my $result = GetOptions (
                'one' => \$opt_one,
                'immediate' => \$opt_immediate,
                'expected-failures=s' => \$opt_expected_failures,
-               'skip=s' => \$opt_skip,
+               'exclude=s' => \@opt_exclude,
+               'include=s' => \@opt_include,
                'srcdir=s' => \$srcdir,
                'builddir=s' => \$builddir,
                'verbose' => \$opt_verbose,
@@ -317,6 +334,7 @@ my $result = GetOptions (
                'resetup-environment' => \$opt_resetup_env,
                'bindir:s' => \$opt_bindir,
                'format=s' => \$opt_format,
+               'testlist=s' => \@testlists
            );
 
 exit(1) if (not $result);
@@ -335,7 +353,7 @@ my $old_pwd = "$RealBin/..";
 
 # Backwards compatibility:
 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
-       if (defined($ENV{FEDORA_DS_PREFIX})) {
+       if (defined($ENV{FEDORA_DS_ROOT})) {
                $ldap = "fedora-ds";
        } else {
                $ldap = "openldap";
@@ -364,31 +382,32 @@ die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
 
 $ENV{PREFIX} = $prefix;
+$ENV{KRB5CCNAME} = "$prefix/krb5ticket";
 $ENV{PREFIX_ABS} = $prefix_abs;
 $ENV{SRCDIR} = $srcdir;
 $ENV{SRCDIR_ABS} = $srcdir_abs;
 
-my $tls_enabled = not $opt_quick;
 if (defined($ENV{RUN_FROM_BUILD_FARM}) and 
        ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
        $opt_format = "buildfarm";
 }
 
+my $tls_enabled = not $opt_quick;
 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
-$ENV{LD_LDB_MODULE_PATH} = "$old_pwd/bin/modules/ldb";
+$ENV{LDB_MODULES_PATH} = "$old_pwd/bin/modules/ldb";
 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
-if (defined($ENV{LD_LIBRARY_PATH})) {
-       $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared:$ENV{LD_LIBRARY_PATH}";
-} else {
-       $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared";
-}
 if (defined($ENV{PKG_CONFIG_PATH})) {
        $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
 } else { 
        $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
 }
-$ENV{PATH} = "$old_pwd/bin:$ENV{PATH}";
+# Required for smbscript:
+$ENV{PATH} = "$old_pwd/bin:$old_pwd:$ENV{PATH}";
 
+if ($opt_socket_wrapper_keep_pcap) {
+       # Socket wrapper keep pcap implies socket wrapper pcap
+       $opt_socket_wrapper_pcap = 1;
+}
 
 if ($opt_socket_wrapper_pcap) {
        # Socket wrapper pcap implies socket wrapper
@@ -404,37 +423,59 @@ if ($opt_socket_wrapper) {
 }
 
 my $target;
+my $testenv_default = "none";
 
 if ($opt_target eq "samba4") {
+       $testenv_default = "member";
+       require target::Samba4;
        $target = new Samba4($opt_bindir or "$srcdir/bin", $ldap, "$srcdir/setup");
 } elsif ($opt_target eq "samba3") {
        if ($opt_socket_wrapper and `$opt_bindir/smbd -b | grep SOCKET_WRAPPER` eq "") {
                die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'.  Exiting....");
        }
-
+       $testenv_default = "dc";
+       require target::Samba3;
        $target = new Samba3($opt_bindir);
 } elsif ($opt_target eq "win") {
        die("Windows tests will not run with socket wrapper enabled.") 
                if ($opt_socket_wrapper);
+       $testenv_default = "dc";
+       require target::Windows;
        $target = new Windows();
 }
 
-if (defined($opt_expected_failures)) {
-       open(KNOWN, "<$opt_expected_failures") or die("unable to read known failures file: $!");
-       while (<KNOWN>) { 
+sub read_test_regexes($)
+{
+       my ($name) = @_;
+       my @ret = ();
+       open(LF, "<$name") or die("unable to read $name: $!");
+       while (<LF>) { 
                chomp; 
-               s/([ \t]+)\#(.*)$//;
-               push (@expected_failures, $_); }
-       close(KNOWN);
+               if (/^(.*?)([ \t]+)\#([\t ]*)(.*?)$/) {
+                       push (@ret, [$1, $4]);
+               } else {
+                       s/^(.*?)([ \t]+)\#([\t ]*)(.*?)$//;
+                       push (@ret, [$_, undef]); 
+               }
+       }
+       close(LF);
+       return @ret;
 }
 
-if (defined($opt_skip)) {
-       open(SKIP, "<$opt_skip") or die("unable to read skip file: $!");
-       while (<SKIP>) { 
-               chomp; 
-               s/([ \t]+)\#(.*)$//;
-               push (@skips, $_); }
-       close(SKIP);
+if (defined($opt_expected_failures)) {
+       @expected_failures = read_test_regexes($opt_expected_failures);
+}
+
+foreach (@opt_exclude) {
+       push (@excludes, read_test_regexes($_));
+}
+
+if ($opt_quick) {
+       push (@includes, read_test_regexes("samba4-quick"));
+}
+
+foreach (@opt_include) {
+       push (@includes, read_test_regexes($_));
 }
 
 my $interfaces = join(',', ("127.0.0.6/8", 
@@ -494,17 +535,17 @@ sub write_clientconf($$)
        torture:basedir = $prefix_abs/client
 #We don't want to pass our self-tests if the PAC code is wrong
        gensec:require_pac = true
+       modules dir = $ENV{LD_SAMBA_MODULE_PATH}
 ";
        close(CF);
 }
 
-
 my @torture_options = ();
 push (@torture_options, "--configfile=$conffile");
 # ensure any one smbtorture call doesn't run too long
 push (@torture_options, "--maximum-runtime=$torture_maxtime");
 push (@torture_options, "--target=$opt_target");
-push (@torture_options, "--basedir=$prefix");
+push (@torture_options, "--basedir=$prefix_abs");
 push (@torture_options, "--option=torture:progress=no") if ($opt_format eq "buildfarm");
 push (@torture_options, "--format=subunit");
 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
@@ -520,28 +561,76 @@ $ENV{CONFIGURATION} = "--configfile=$conffile";
 
 my %required_envs = ();
 
-if ($opt_quick) {
-       open(IN, "$testsdir/tests_quick.sh|");
-} else {
-       open(IN, "$testsdir/tests_all.sh|");
-}
-while (<IN>) {
-       if ($_ eq "-- TEST --\n") {
-               my $name = <IN>;
-               $name =~ s/\n//g;
-               my $env = <IN>;
-               $env =~ s/\n//g;
-               my $cmdline = <IN>;
-               $cmdline =~ s/\n//g;
-               if (not defined($tests) or $name =~ /$tests/) {
-                       $required_envs{$env} = 1;
-                       push (@todo, [$name, $env, $cmdline]);
+sub read_testlist($)
+{
+       my ($filename) = @_;
+
+       my @ret = ();
+       open(IN, $filename) or die("Unable to open $filename: $!");
+
+       while (<IN>) {
+               if ($_ eq "-- TEST --\n") {
+                       my $name = <IN>;
+                       $name =~ s/\n//g;
+                       my $env = <IN>;
+                       $env =~ s/\n//g;
+                       my $cmdline = <IN>;
+                       $cmdline =~ s/\n//g;
+                       if (not defined($tests) or $name =~ /$tests/) {
+                               $required_envs{$env} = 1;
+                               push (@ret, [$name, $env, $cmdline]);
+                       }
+               } else {
+                       print;
                }
+       }
+       close(IN) or die("Error creating recipe");
+       return @ret;
+}
+
+if ($#testlists == -1) {
+       die("No testlists specified");
+}
+
+my @available = ();
+foreach my $fn (@testlists) {
+       foreach (read_testlist($fn)) {
+               my $name = $$_[0];
+               next if (@includes and not find_in_list(\@includes, $name));
+               push (@available, $_);
+       }
+}
+
+my $msg_ops;
+if ($opt_format eq "buildfarm") {
+       require output::buildfarm;
+       $msg_ops = new output::buildfarm($statistics);
+} elsif ($opt_format eq "plain") {
+       require output::plain;
+       $msg_ops = new output::plain("$prefix/summary", $opt_verbose, $opt_immediate, $statistics, $#available+1);
+} elsif ($opt_format eq "html") {
+       require output::html;
+       mkdir("test-results", 0777);
+       $msg_ops = new output::html("test-results", $statistics);
+} else {
+       die("Invalid output format '$opt_format'");
+}
+
+
+foreach (@available) {
+       my $name = $$_[0];
+       my $skipreason = skip($name);
+       if ($skipreason) {
+               $msg_ops->skip_testsuite($name, $skipreason);
        } else {
-               print;
+               push(@todo, $_); 
        }
 }
-close(IN) or die("Error creating recipe");
+
+if ($#todo == -1) {
+       print STDERR "No tests to run\n";
+       exit(1);
+       }
 
 my $suitestotal = $#todo + 1;
 my $i = 0;
@@ -574,9 +663,16 @@ my @exported_envvars = (
 
        # misc stuff
        "KRB5_CONFIG",
-       "WINBINDD_SOCKET_DIR"
+       "WINBINDD_SOCKET_DIR",
+       "WINBINDD_PRIV_PIPE_DIR"
 );
 
+$SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub { 
+       my $signame = shift;
+       teardown_env($_) foreach(keys %running_envs);
+       die("Received signal $signame");
+};
+
 sub setup_env($)
 {
        my ($envname) = @_;
@@ -595,6 +691,8 @@ sub setup_env($)
 
        return undef unless defined($testenv_vars);
 
+       $running_envs{$envname} = $testenv_vars;
+
        SocketWrapper::set_default_iface(6);
        write_clientconf($conffile, $testenv_vars);
 
@@ -606,7 +704,6 @@ sub setup_env($)
                }
        }
 
-       $running_envs{$envname} = $testenv_vars;
        return $testenv_vars;
 }
 
@@ -645,28 +742,13 @@ sub teardown_env($)
        delete $running_envs{$envname};
 }
 
-my $msg_ops;
-if ($opt_format eq "buildfarm") {
-       require output::buildfarm;
-       $msg_ops = new output::buildfarm();
-} elsif ($opt_format eq "plain") {
-       require output::plain;
-       $msg_ops = new output::plain($opt_verbose, $opt_immediate, $statistics);
-} elsif ($opt_format eq "html") {
-       require output::html;
-       mkdir("test-results", 0777);
-       $msg_ops = new output::html("test-results", $statistics);
-} else {
-       die("Invalid output format '$opt_format'");
-}
-
 if ($opt_no_lazy_setup) {
        setup_env($_) foreach (keys %required_envs);
 }
 
 if ($opt_testenv) {
        my $testenv_name = $ENV{SELFTEST_TESTENV};
-       $testenv_name = "member" unless defined($testenv_name);
+       $testenv_name = $testenv_default unless defined($testenv_name);
 
        my $testenv_vars = setup_env($testenv_name);
 
@@ -686,7 +768,7 @@ TORTURE_OPTIONS=\$TORTURE_OPTIONS
 CONFIGURATION=\$CONFIGURATION
 
 $envvarstr
-\" && bash'");
+\" && LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} bash'");
        teardown_env($testenv_name);
 } else {
        foreach (@todo) {
@@ -696,21 +778,14 @@ $envvarstr
                my $name = $$_[0];
                my $envname = $$_[1];
                
-               if (skip($name)) {
-                       $msg_ops->skip_testsuite($envname, $name);
-                       $statistics->{SUITES_SKIPPED}++;
-                       next;
-               }
-
                my $envvars = setup_env($envname);
                if (not defined($envvars)) {
-                       $statistics->{SUITES_FAIL}++;
-                       $statistics->{TESTS_ERROR}++;
-                       $msg_ops->missing_env($name, $envname);
+                       $msg_ops->skip_testsuite($name, "unable to set up environment $envname");
                        next;
                }
 
-               run_testsuite($envname, $name, $cmd, $i, $suitestotal, $msg_ops);
+               run_testsuite($envname, $name, $cmd, $i, $suitestotal, 
+                             $msg_ops);
 
                if (defined($opt_analyse_cmd)) {
                        system("$opt_analyse_cmd \"$name\"");
@@ -726,10 +801,7 @@ teardown_env($_) foreach (keys %running_envs);
 
 $target->stop();
 
-$statistics->{END_TIME} = time();
-my $duration = ($statistics->{END_TIME}-$statistics->{START_TIME});
 $msg_ops->summary();
-print "DURATION: $duration seconds\n";
 
 my $failed = 0;