2 # Bootstrap Samba and run a number of tests against it.
3 # Copyright (C) 2005-2007 Jelmer Vernooij <jelmer@samba.org>
4 # Published under the GNU GPL, v3 or later.
10 selftest - Samba test runner
16 selftest [--srcdir=DIR] [--builddir=DIR] [--target=samba4|samba3|win] [--socket-wrapper] [--quick] [--exclude=FILE] [--include=FILE] [--one] [--prefix=prefix] [--immediate] [--testlist=FILE] [TESTS]
20 A simple test runner. TESTS is a regular expression with tests to run.
28 Show list of available options.
34 =item I<--builddir=DIR>
40 Change directory to run tests in. Default is 'st'.
44 Show errors as soon as they happen rather than at the end of the test run.
46 =item I<--target samba4|samba3|win>
48 Specify test target against which to run. Default is 'samba4'.
52 Run only a limited number of tests. Intended to run in about 30 seconds on
53 moderately recent systems.
55 =item I<--socket-wrapper>
57 Use socket wrapper library for communication with server. Only works
58 when the server is running locally.
60 Will prevent TCP and UDP ports being opened on the local host but
61 (transparently) redirects these calls to use unix domain sockets.
63 =item I<--expected-failures>
65 Specify a file containing a list of tests that are expected to fail. Failures for
66 these tests will be counted as successes, successes will be counted as failures.
68 The format for the file is, one entry per line:
70 TESTSUITE-NAME/TEST-NAME
72 The reason for a test can also be specified, by adding a hash sign (#) and the reason
77 Specify a file containing a list of tests that should be skipped. Possible
78 candidates are tests that segfault the server, flip or don't end. The format of this file is the same as
79 for the --expected-failures flag.
83 Specify a file containing a list of tests that should be run. Same format
84 as the --exclude flag.
86 Not includes specified means all tests will be run.
90 Abort as soon as one test fails.
94 Load a list of tests from the specified location.
102 =item I<SMBD_VALGRIND>
104 =item I<TORTURE_MAXTIME>
116 selftest is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
126 use FindBin qw($RealBin $Script);
130 use Cwd qw(abs_path);
132 use Subunit qw(parse_results);
139 my $opt_target = "samba4";
141 my $opt_socket_wrapper = 0;
142 my $opt_socket_wrapper_pcap = undef;
143 my $opt_socket_wrapper_keep_pcap = undef;
145 my $opt_immediate = 0;
146 my $opt_expected_failures = undef;
147 my @opt_exclude = ();
148 my @opt_include = ();
152 my $opt_analyse_cmd = undef;
153 my $opt_resetup_env = undef;
154 my $opt_bindir = undef;
155 my $opt_no_lazy_setup = undef;
156 my $opt_format = "plain";
163 my @expected_failures = ();
168 START_TIME => time(),
174 TESTS_UNEXPECTED_OK => 0,
175 TESTS_EXPECTED_OK => 0,
176 TESTS_UNEXPECTED_FAIL => 0,
177 TESTS_EXPECTED_FAIL => 0,
184 my ($list, $fullname) = @_;
187 if ($fullname =~ /$$_[0]/) {
188 return ($$_[1]) if ($$_[1]);
189 return "NO REASON SPECIFIED";
196 sub expecting_failure($)
199 return find_in_list(\@expected_failures, $name);
206 return find_in_list(\@excludes, $name);
215 return unless ($opt_socket_wrapper_pcap);
216 return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
218 my $fname = sprintf("t%03u_%s", $state->{INDEX}, $state->{NAME});
219 $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
221 $state->{PCAP_FILE} = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
223 SocketWrapper::setup_pcap($state->{PCAP_FILE});
226 sub cleanup_pcap($$$)
228 my ($state, $expected_ret, $ret) = @_;
230 return unless ($opt_socket_wrapper_pcap);
231 return if ($opt_socket_wrapper_keep_pcap);
232 return unless ($expected_ret == $ret);
233 return unless defined($state->{PCAP_FILE});
235 unlink($state->{PCAP_FILE});
236 $state->{PCAP_FILE} = undef;
239 sub run_testsuite($$$$$$$)
241 my ($envname, $envvars, $name, $cmd, $i, $totalsuites, $msg_ops) = @_;
248 TOTAL => $totalsuites,
252 setup_pcap($msg_state);
254 $msg_ops->start_test($msg_state, [], $name);
256 open(RESULT, "$cmd 2>&1|");
257 my $expected_ret = parse_results(
258 $msg_ops, $msg_state, $statistics, *RESULT, \&expecting_failure, [$name]);
260 my $envlog = getlog_env($envname);
261 $msg_ops->output_msg($msg_state, "ENVLOG: $envlog\n") if ($envlog ne "");
263 my $ret = close(RESULT);
264 $ret = 0 unless $ret == 1;
267 $msg_ops->end_test($msg_state, [], $name, "success", $expected_ret != $ret, undef);
269 $msg_ops->end_test($msg_state, [], $name, "failure", $expected_ret != $ret,
273 cleanup_pcap($msg_state, $expected_ret, $ret);
275 if (not $opt_socket_wrapper_keep_pcap and
276 defined($msg_state->{PCAP_FILE})) {
277 $msg_ops->output_msg($msg_state,
278 "PCAP FILE: $msg_state->{PCAP_FILE}\n");
281 if ($ret != $expected_ret) {
282 $statistics->{SUITES_FAIL}++;
283 exit(1) if ($opt_one);
285 $statistics->{SUITES_OK}++;
288 return ($ret == $expected_ret);
293 print "Samba test runner
294 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
296 Usage: $Script [OPTIONS] PREFIX
299 --help this help page
300 --target=samba4|samba3|win Samba version to target
301 --testlist=FILE file to read available tests from
304 --prefix=DIR prefix to run tests in [st]
305 --srcdir=DIR source directory [.]
306 --builddir=DIR output directory [.]
309 --socket-wrapper-pcap save traffic to pcap directories
310 --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that
312 --socket-wrapper enable socket wrapper
313 --expected-failures=FILE specify list of tests that is guaranteed to fail
316 --ldap=openldap|fedora-ds back smbd onto specified ldap server
319 --bindir=PATH path to binaries
322 --quick run quick overall test
323 --one abort when the first test fails
324 --immediate print test output for failed tests during run
326 --analyse-cmd CMD command to run after each test
331 my $result = GetOptions (
332 'help|h|?' => \$opt_help,
333 'target=s' => \$opt_target,
334 'prefix=s' => \$prefix,
335 'socket-wrapper' => \$opt_socket_wrapper,
336 'socket-wrapper-pcap' => \$opt_socket_wrapper_pcap,
337 'socket-wrapper-keep-pcap' => \$opt_socket_wrapper_keep_pcap,
338 'quick' => \$opt_quick,
340 'immediate' => \$opt_immediate,
341 'expected-failures=s' => \$opt_expected_failures,
342 'exclude=s' => \@opt_exclude,
343 'include=s' => \@opt_include,
344 'srcdir=s' => \$srcdir,
345 'builddir=s' => \$builddir,
346 'verbose' => \$opt_verbose,
347 'testenv' => \$opt_testenv,
349 'analyse-cmd=s' => \$opt_analyse_cmd,
350 'no-lazy-setup' => \$opt_no_lazy_setup,
351 'resetup-environment' => \$opt_resetup_env,
352 'bindir:s' => \$opt_bindir,
353 'format=s' => \$opt_format,
354 'testlist=s' => \@testlists
357 exit(1) if (not $result);
359 ShowHelp() if ($opt_help);
363 # quick hack to disable rpc validation when using valgrind - its way too slow
364 unless (defined($ENV{VALGRIND})) {
365 $ENV{VALIDATE} = "validate";
366 $ENV{MALLOC_CHECK_} = 2;
369 my $old_pwd = "$RealBin/..";
371 # Backwards compatibility:
372 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
373 if (defined($ENV{FEDORA_DS_PREFIX})) {
380 my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
383 $torture_maxtime *= 2;
390 die("using an empty prefix isn't allowed") unless $prefix ne "";
392 #Ensure we have the test prefix around
393 mkdir($prefix, 0777) unless -d $prefix;
395 my $prefix_abs = abs_path($prefix);
396 my $srcdir_abs = abs_path($srcdir);
398 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
399 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
401 $ENV{PREFIX} = $prefix;
402 $ENV{PREFIX_ABS} = $prefix_abs;
403 $ENV{SRCDIR} = $srcdir;
404 $ENV{SRCDIR_ABS} = $srcdir_abs;
406 if (defined($ENV{RUN_FROM_BUILD_FARM}) and
407 ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
408 $opt_format = "buildfarm";
411 my $tls_enabled = not $opt_quick;
412 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
413 $ENV{LDB_MODULES_PATH} = "$old_pwd/bin/modules/ldb";
414 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
415 if (defined($ENV{PKG_CONFIG_PATH})) {
416 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
418 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
420 # Required for smbscript:
421 $ENV{PATH} = "$old_pwd/bin:$old_pwd:$ENV{PATH}";
423 if ($opt_socket_wrapper_keep_pcap) {
424 # Socket wrapper keep pcap implies socket wrapper pcap
425 $opt_socket_wrapper_pcap = 1;
428 if ($opt_socket_wrapper_pcap) {
429 # Socket wrapper pcap implies socket wrapper
430 $opt_socket_wrapper = 1;
433 my $socket_wrapper_dir;
434 if ($opt_socket_wrapper) {
435 $socket_wrapper_dir = SocketWrapper::setup_dir("$prefix/w", $opt_socket_wrapper_pcap);
436 print "SOCKET_WRAPPER_DIR=$socket_wrapper_dir\n";
438 warn("Not using socket wrapper, but also not running as root. Will not be able to listen on proper ports") unless $< == 0;
442 my $testenv_default = "none";
444 if ($opt_target eq "samba4") {
445 $testenv_default = "member";
446 $target = new Samba4($opt_bindir or "$srcdir/bin", $ldap, "$srcdir/setup");
447 } elsif ($opt_target eq "samba3") {
448 if ($opt_socket_wrapper and `$opt_bindir/smbd -b | grep SOCKET_WRAPPER` eq "") {
449 die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....");
451 $testenv_default = "dc";
452 $target = new Samba3($opt_bindir);
453 } elsif ($opt_target eq "win") {
454 die("Windows tests will not run with socket wrapper enabled.")
455 if ($opt_socket_wrapper);
456 $testenv_default = "dc";
457 $target = new Windows();
460 sub read_test_regexes($)
464 open(LF, "<$name") or die("unable to read $name: $!");
467 if (/^(.*?)([ \t]+)\#([\t ]*)(.*?)$/) {
468 push (@ret, [$1, $4]);
470 s/^(.*?)([ \t]+)\#([\t ]*)(.*?)$//;
471 push (@ret, [$_, undef]);
478 if (defined($opt_expected_failures)) {
479 @expected_failures = read_test_regexes($opt_expected_failures);
482 foreach (@opt_exclude) {
483 push (@excludes, read_test_regexes($_));
487 push (@includes, read_test_regexes("samba4-quick"));
490 foreach (@opt_include) {
491 push (@includes, read_test_regexes($_));
494 my $interfaces = join(',', ("127.0.0.6/8",
501 my $conffile = "$prefix_abs/client/client.conf";
503 sub write_clientconf($$)
505 my ($conffile, $vars) = @_;
507 mkdir("$prefix/client", 0777) unless -d "$prefix/client";
509 if ( -d "$prefix/client/private" ) {
510 unlink <$prefix/client/private/*>;
512 mkdir("$prefix/client/private", 0777);
515 open(CF, ">$conffile");
516 print CF "[global]\n";
517 if (defined($ENV{VALGRIND})) {
518 print CF "\ticonv:native = true\n";
520 print CF "\ticonv:native = false\n";
522 print CF "\tnetbios name = client\n";
523 if (defined($vars->{DOMAIN})) {
524 print CF "\tworkgroup = $vars->{DOMAIN}\n";
526 if (defined($vars->{REALM})) {
527 print CF "\trealm = $vars->{REALM}\n";
529 if (defined($vars->{NCALRPCDIR})) {
530 print CF "\tncalrpc dir = $vars->{NCALRPCDIR}\n";
532 if (defined($vars->{PIDDIR})) {
533 print CF "\tpid directory = $vars->{PIDDIR}\n";
535 if (defined($vars->{WINBINDD_SOCKET_DIR})) {
536 print CF "\twinbindd socket directory = $vars->{WINBINDD_SOCKET_DIR}\n";
539 private dir = $prefix_abs/client/private
540 js include = $srcdir_abs/scripting/libjs
541 name resolve order = bcast
542 interfaces = $interfaces
543 panic action = $srcdir_abs/script/gdb_backtrace \%PID\% \%PROG\%
545 notify:inotify = false
547 system:anonymous = true
548 torture:basedir = $prefix_abs/client
549 #We don't want to pass our self-tests if the PAC code is wrong
550 gensec:require_pac = true
551 modules dir = $ENV{LD_SAMBA_MODULE_PATH}
557 my @torture_options = ();
558 push (@torture_options, "--configfile=$conffile");
559 # ensure any one smbtorture call doesn't run too long
560 push (@torture_options, "--maximum-runtime=$torture_maxtime");
561 push (@torture_options, "--target=$opt_target");
562 push (@torture_options, "--basedir=$prefix_abs");
563 push (@torture_options, "--option=torture:progress=no") if ($opt_format eq "buildfarm");
564 push (@torture_options, "--format=subunit");
565 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
567 $ENV{TORTURE_OPTIONS} = join(' ', @torture_options);
568 print "OPTIONS $ENV{TORTURE_OPTIONS}\n";
572 my $testsdir = "$srcdir/selftest";
573 $ENV{SMB_CONF_PATH} = "$conffile";
574 $ENV{CONFIGURATION} = "--configfile=$conffile";
576 my %required_envs = ();
583 open(IN, $filename) or die("Unable to open $filename: $!");
586 if ($_ eq "-- TEST --\n") {
593 if (not defined($tests) or $name =~ /$tests/) {
594 $required_envs{$env} = 1;
595 push (@ret, [$name, $env, $cmdline]);
601 close(IN) or die("Error creating recipe");
605 if ($#testlists == -1) {
606 die("No testlists specified");
610 if ($opt_format eq "buildfarm") {
611 require output::buildfarm;
612 $msg_ops = new output::buildfarm($statistics);
613 } elsif ($opt_format eq "plain") {
614 require output::plain;
615 $msg_ops = new output::plain("$prefix/summary", $opt_verbose, $opt_immediate, $statistics);
616 } elsif ($opt_format eq "html") {
617 require output::html;
618 mkdir("test-results", 0777);
619 $msg_ops = new output::html("test-results", $statistics);
621 die("Invalid output format '$opt_format'");
624 foreach my $fn (@testlists) {
625 foreach (read_testlist($fn)) {
627 next if (@includes and not find_in_list(\@includes, $name));
628 my $skipreason = skip($name);
630 $msg_ops->skip_testsuite($name, $skipreason);
631 $statistics->{SUITES_SKIPPED}++;
639 print STDERR "No tests to run\n";
643 my $suitestotal = $#todo + 1;
647 my %running_envs = ();
649 my @exported_envvars = (
654 # domain controller stuff
674 "WINBINDD_SOCKET_DIR",
675 "WINBINDD_PRIV_PIPE_DIR"
678 $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
680 teardown_env($_) foreach(keys %running_envs);
681 die("Received signal $signame");
689 if ($envname eq "none") {
691 } elsif (defined($running_envs{$envname})) {
692 $testenv_vars = $running_envs{$envname};
693 if (not $target->check_env($testenv_vars)) {
694 $testenv_vars = undef;
697 $testenv_vars = $target->setup_env($envname, $prefix);
700 return undef unless defined($testenv_vars);
702 $running_envs{$envname} = $testenv_vars;
704 SocketWrapper::set_default_iface(6);
705 write_clientconf($conffile, $testenv_vars);
707 foreach (@exported_envvars) {
708 if (defined($testenv_vars->{$_})) {
709 $ENV{$_} = $testenv_vars->{$_};
715 return $testenv_vars;
718 sub exported_envvars_str($)
720 my ($testenv_vars) = @_;
723 foreach (@exported_envvars) {
724 next unless defined($testenv_vars->{$_});
725 $out .= $_."=".$testenv_vars->{$_}."\n";
734 return "" if ($envname eq "none");
735 return $target->getlog_env($running_envs{$envname});
741 return 1 if ($envname eq "none");
742 return $target->check_env($running_envs{$envname});
748 return if ($envname eq "none");
749 $target->teardown_env($running_envs{$envname});
750 delete $running_envs{$envname};
754 if ($opt_no_lazy_setup) {
755 setup_env($_) foreach (keys %required_envs);
759 my $testenv_name = $ENV{SELFTEST_TESTENV};
760 $testenv_name = $testenv_default unless defined($testenv_name);
762 my $testenv_vars = setup_env($testenv_name);
764 $ENV{PIDDIR} = $testenv_vars->{PIDDIR};
766 my $envvarstr = exported_envvars_str($testenv_vars);
768 my $term = ($ENV{TERM} or "xterm");
769 system("$term -e 'echo -e \"
770 Welcome to the Samba4 Test environment '$testenv_name'
772 This matches the client environment used in make test
773 smbd is pid `cat \$PIDDIR/smbd.pid`
775 Some useful environment variables:
776 TORTURE_OPTIONS=\$TORTURE_OPTIONS
777 CONFIGURATION=\$CONFIGURATION
781 teardown_env($testenv_name);
786 $cmd =~ s/([\(\)])/\\$1/g;
788 my $envname = $$_[1];
790 my $envvars = setup_env($envname);
791 if (not defined($envvars)) {
792 $statistics->{SUITES_SKIPPED}++;
793 $msg_ops->skip_testsuite($name, "unable to set up environment $envname");
797 run_testsuite($envname, $envvars, $name, $cmd, $i, $suitestotal,
800 if (defined($opt_analyse_cmd)) {
801 system("$opt_analyse_cmd \"$name\"");
804 teardown_env($envname) if ($opt_resetup_env);
810 teardown_env($_) foreach (keys %running_envs);
814 $statistics->{END_TIME} = time();
815 my $duration = ($statistics->{END_TIME}-$statistics->{START_TIME});
817 print "DURATION: $duration seconds\n";
821 # if there were any valgrind failures, show them
822 foreach (<$prefix/valgrind.log*>) {
824 system("grep DWARF2.CFI.reader $_ > /dev/null");
826 print "VALGRIND FAILURE\n";
832 if ($opt_format eq "buildfarm") {
833 print "TEST STATUS: $statistics->{SUITES_FAIL}\n";
836 exit $statistics->{SUITES_FAIL};