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 my $reason = find_in_list(\@excludes, $name);
208 return $reason if $reason;
210 return undef unless ($#includes > -1);
212 return "not included" if (not find_in_list(\@includes, $name));
223 return unless ($opt_socket_wrapper_pcap);
224 return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
226 my $fname = sprintf("t%03u_%s", $state->{INDEX}, $state->{NAME});
227 $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
229 $state->{PCAP_FILE} = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
231 SocketWrapper::setup_pcap($state->{PCAP_FILE});
234 sub cleanup_pcap($$$)
236 my ($state, $expected_ret, $ret) = @_;
238 return unless ($opt_socket_wrapper_pcap);
239 return if ($opt_socket_wrapper_keep_pcap);
240 return unless ($expected_ret == $ret);
241 return unless defined($state->{PCAP_FILE});
243 unlink($state->{PCAP_FILE});
244 $state->{PCAP_FILE} = undef;
247 sub run_testsuite($$$$$$$)
249 my ($envname, $envvars, $name, $cmd, $i, $totalsuites, $msg_ops) = @_;
256 TOTAL => $totalsuites,
260 setup_pcap($msg_state);
262 open(RESULT, "$cmd 2>&1|");
263 $msg_ops->start_testsuite($msg_state);
265 my $expected_ret = parse_results(
266 $msg_ops, $msg_state, $statistics, *RESULT, \&expecting_failure);
268 my $ret = close(RESULT);
269 $ret = 0 unless $ret == 1;
271 cleanup_pcap($msg_state, $expected_ret, $ret);
273 $msg_ops->end_testsuite($msg_state, $expected_ret, $ret,
274 getlog_env($msg_state->{ENVNAME}));
276 if (not $opt_socket_wrapper_keep_pcap and
277 defined($msg_state->{PCAP_FILE})) {
278 $msg_ops->output_msg($msg_state,
279 "PCAP FILE: $msg_state->{PCAP_FILE}\n");
282 if ($ret != $expected_ret) {
283 $statistics->{SUITES_FAIL}++;
284 exit(1) if ($opt_one);
286 $statistics->{SUITES_OK}++;
289 return ($ret == $expected_ret);
294 print "Samba test runner
295 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
297 Usage: $Script [OPTIONS] PREFIX
300 --help this help page
301 --target=samba4|samba3|win Samba version to target
302 --testlist=FILE file to read available tests from
305 --prefix=DIR prefix to run tests in [st]
306 --srcdir=DIR source directory [.]
307 --builddir=DIR output directory [.]
310 --socket-wrapper-pcap save traffic to pcap directories
311 --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that
313 --socket-wrapper enable socket wrapper
314 --expected-failures=FILE specify list of tests that is guaranteed to fail
317 --ldap=openldap|fedora-ds back smbd onto specified ldap server
320 --bindir=PATH path to binaries
323 --quick run quick overall test
324 --one abort when the first test fails
325 --immediate print test output for failed tests during run
327 --analyse-cmd CMD command to run after each test
332 my $result = GetOptions (
333 'help|h|?' => \$opt_help,
334 'target=s' => \$opt_target,
335 'prefix=s' => \$prefix,
336 'socket-wrapper' => \$opt_socket_wrapper,
337 'socket-wrapper-pcap' => \$opt_socket_wrapper_pcap,
338 'socket-wrapper-keep-pcap' => \$opt_socket_wrapper_keep_pcap,
339 'quick' => \$opt_quick,
341 'immediate' => \$opt_immediate,
342 'expected-failures=s' => \$opt_expected_failures,
343 'exclude=s' => \@opt_exclude,
344 'include=s' => \@opt_include,
345 'srcdir=s' => \$srcdir,
346 'builddir=s' => \$builddir,
347 'verbose' => \$opt_verbose,
348 'testenv' => \$opt_testenv,
350 'analyse-cmd=s' => \$opt_analyse_cmd,
351 'no-lazy-setup' => \$opt_no_lazy_setup,
352 'resetup-environment' => \$opt_resetup_env,
353 'bindir:s' => \$opt_bindir,
354 'format=s' => \$opt_format,
355 'testlist=s' => \@testlists
358 exit(1) if (not $result);
360 ShowHelp() if ($opt_help);
364 # quick hack to disable rpc validation when using valgrind - its way too slow
365 unless (defined($ENV{VALGRIND})) {
366 $ENV{VALIDATE} = "validate";
367 $ENV{MALLOC_CHECK_} = 2;
370 my $old_pwd = "$RealBin/..";
372 # Backwards compatibility:
373 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
374 if (defined($ENV{FEDORA_DS_PREFIX})) {
381 my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
384 $torture_maxtime *= 2;
391 die("using an empty prefix isn't allowed") unless $prefix ne "";
393 #Ensure we have the test prefix around
394 mkdir($prefix, 0777) unless -d $prefix;
396 my $prefix_abs = abs_path($prefix);
397 my $srcdir_abs = abs_path($srcdir);
399 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
400 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
402 $ENV{PREFIX} = $prefix;
403 $ENV{PREFIX_ABS} = $prefix_abs;
404 $ENV{SRCDIR} = $srcdir;
405 $ENV{SRCDIR_ABS} = $srcdir_abs;
407 if (defined($ENV{RUN_FROM_BUILD_FARM}) and
408 ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
409 $opt_format = "buildfarm";
412 my $tls_enabled = not $opt_quick;
413 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
414 $ENV{LD_LDB_MODULE_PATH} = "$old_pwd/bin/modules/ldb";
415 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
416 if (defined($ENV{LD_LIBRARY_PATH})) {
417 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared:$ENV{LD_LIBRARY_PATH}";
419 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared";
421 if (defined($ENV{PKG_CONFIG_PATH})) {
422 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
424 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
426 # Required for smbscript:
427 $ENV{PATH} = "$old_pwd/bin:$old_pwd:$ENV{PATH}";
429 if ($opt_socket_wrapper_keep_pcap) {
430 # Socket wrapper keep pcap implies socket wrapper pcap
431 $opt_socket_wrapper_pcap = 1;
434 if ($opt_socket_wrapper_pcap) {
435 # Socket wrapper pcap implies socket wrapper
436 $opt_socket_wrapper = 1;
439 my $socket_wrapper_dir;
440 if ($opt_socket_wrapper) {
441 $socket_wrapper_dir = SocketWrapper::setup_dir("$prefix/w", $opt_socket_wrapper_pcap);
442 print "SOCKET_WRAPPER_DIR=$socket_wrapper_dir\n";
444 warn("Not using socket wrapper, but also not running as root. Will not be able to listen on proper ports") unless $< == 0;
448 my $testenv_default = "none";
450 if ($opt_target eq "samba4") {
451 $testenv_default = "member";
452 $target = new Samba4($opt_bindir or "$srcdir/bin", $ldap, "$srcdir/setup");
453 } elsif ($opt_target eq "samba3") {
454 if ($opt_socket_wrapper and `$opt_bindir/smbd -b | grep SOCKET_WRAPPER` eq "") {
455 die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....");
457 $testenv_default = "dc";
458 $target = new Samba3($opt_bindir);
459 } elsif ($opt_target eq "win") {
460 die("Windows tests will not run with socket wrapper enabled.")
461 if ($opt_socket_wrapper);
462 $testenv_default = "dc";
463 $target = new Windows();
466 sub read_test_regexes($)
470 open(LF, "<$name") or die("unable to read $name: $!");
473 if (/^(.*?)([ \t]+)\#(.*)$/) {
474 push (@ret, [$1, $3]);
476 s/^(.*?)([ \t]+)\#(.*)$//;
477 push (@ret, [$_, undef]);
484 if (defined($opt_expected_failures)) {
485 @expected_failures = read_test_regexes($opt_expected_failures);
488 foreach (@opt_exclude) {
489 push (@excludes, read_test_regexes($_));
493 push (@includes, read_test_regexes("samba4-quick"));
496 foreach (@opt_include) {
497 push (@includes, read_test_regexes($_));
500 my $interfaces = join(',', ("127.0.0.6/8",
507 my $conffile = "$prefix_abs/client/client.conf";
509 sub write_clientconf($$)
511 my ($conffile, $vars) = @_;
513 mkdir("$prefix/client", 0777) unless -d "$prefix/client";
515 if ( -d "$prefix/client/private" ) {
516 unlink <$prefix/client/private/*>;
518 mkdir("$prefix/client/private", 0777);
521 open(CF, ">$conffile");
522 print CF "[global]\n";
523 if (defined($ENV{VALGRIND})) {
524 print CF "\ticonv:native = true\n";
526 print CF "\ticonv:native = false\n";
528 print CF "\tnetbios name = client\n";
529 if (defined($vars->{DOMAIN})) {
530 print CF "\tworkgroup = $vars->{DOMAIN}\n";
532 if (defined($vars->{REALM})) {
533 print CF "\trealm = $vars->{REALM}\n";
535 if (defined($vars->{NCALRPCDIR})) {
536 print CF "\tncalrpc dir = $vars->{NCALRPCDIR}\n";
538 if (defined($vars->{PIDDIR})) {
539 print CF "\tpid directory = $vars->{PIDDIR}\n";
541 if (defined($vars->{WINBINDD_SOCKET_DIR})) {
542 print CF "\twinbindd socket directory = $vars->{WINBINDD_SOCKET_DIR}\n";
545 private dir = $prefix_abs/client/private
546 js include = $srcdir_abs/scripting/libjs
547 name resolve order = bcast
548 interfaces = $interfaces
549 panic action = $srcdir_abs/script/gdb_backtrace \%PID\% \%PROG\%
551 notify:inotify = false
553 system:anonymous = true
554 torture:basedir = $prefix_abs/client
555 #We don't want to pass our self-tests if the PAC code is wrong
556 gensec:require_pac = true
562 my @torture_options = ();
563 push (@torture_options, "--configfile=$conffile");
564 # ensure any one smbtorture call doesn't run too long
565 push (@torture_options, "--maximum-runtime=$torture_maxtime");
566 push (@torture_options, "--target=$opt_target");
567 push (@torture_options, "--basedir=$prefix_abs");
568 push (@torture_options, "--option=torture:progress=no") if ($opt_format eq "buildfarm");
569 push (@torture_options, "--format=subunit");
570 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
572 $ENV{TORTURE_OPTIONS} = join(' ', @torture_options);
573 print "OPTIONS $ENV{TORTURE_OPTIONS}\n";
577 my $testsdir = "$srcdir/selftest";
578 $ENV{SMB_CONF_PATH} = "$conffile";
579 $ENV{CONFIGURATION} = "--configfile=$conffile";
581 my %required_envs = ();
588 open(IN, $filename) or die("Unable to open $filename: $!");
591 if ($_ eq "-- TEST --\n") {
598 if (not defined($tests) or $name =~ /$tests/) {
599 $required_envs{$env} = 1;
600 push (@ret, [$name, $env, $cmdline]);
606 close(IN) or die("Error creating recipe");
610 if ($#testlists == -1) {
611 die("No testlists specified");
614 foreach (@testlists) {
615 push(@todo, read_testlist($_));
619 print STDERR "No tests to run\n";
623 my $suitestotal = $#todo + 1;
627 my %running_envs = ();
629 my @exported_envvars = (
634 # domain controller stuff
654 "WINBINDD_SOCKET_DIR",
655 "WINBINDD_PRIV_PIPE_DIR"
658 $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
660 teardown_env($_) foreach(keys %running_envs);
661 die("Received signal $signame");
669 if ($envname eq "none") {
671 } elsif (defined($running_envs{$envname})) {
672 $testenv_vars = $running_envs{$envname};
673 if (not $target->check_env($testenv_vars)) {
674 $testenv_vars = undef;
677 $testenv_vars = $target->setup_env($envname, $prefix);
680 return undef unless defined($testenv_vars);
682 $running_envs{$envname} = $testenv_vars;
684 SocketWrapper::set_default_iface(6);
685 write_clientconf($conffile, $testenv_vars);
687 foreach (@exported_envvars) {
688 if (defined($testenv_vars->{$_})) {
689 $ENV{$_} = $testenv_vars->{$_};
695 return $testenv_vars;
698 sub exported_envvars_str($)
700 my ($testenv_vars) = @_;
703 foreach (@exported_envvars) {
704 next unless defined($testenv_vars->{$_});
705 $out .= $_."=".$testenv_vars->{$_}."\n";
714 return "" if ($envname eq "none");
715 return $target->getlog_env($running_envs{$envname});
721 return 1 if ($envname eq "none");
722 return $target->check_env($running_envs{$envname});
728 return if ($envname eq "none");
729 $target->teardown_env($running_envs{$envname});
730 delete $running_envs{$envname};
734 if ($opt_format eq "buildfarm") {
735 require output::buildfarm;
736 $msg_ops = new output::buildfarm($statistics);
737 } elsif ($opt_format eq "plain") {
738 require output::plain;
739 $msg_ops = new output::plain($opt_verbose, $opt_immediate, $statistics);
740 } elsif ($opt_format eq "html") {
741 require output::html;
742 mkdir("test-results", 0777);
743 $msg_ops = new output::html("test-results", $statistics);
745 die("Invalid output format '$opt_format'");
748 if ($opt_no_lazy_setup) {
749 setup_env($_) foreach (keys %required_envs);
753 my $testenv_name = $ENV{SELFTEST_TESTENV};
754 $testenv_name = $testenv_default unless defined($testenv_name);
756 my $testenv_vars = setup_env($testenv_name);
758 $ENV{PIDDIR} = $testenv_vars->{PIDDIR};
760 my $envvarstr = exported_envvars_str($testenv_vars);
762 my $term = ($ENV{TERM} or "xterm");
763 system("$term -e 'echo -e \"
764 Welcome to the Samba4 Test environment '$testenv_name'
766 This matches the client environment used in make test
767 smbd is pid `cat \$PIDDIR/smbd.pid`
769 Some useful environment variables:
770 TORTURE_OPTIONS=\$TORTURE_OPTIONS
771 CONFIGURATION=\$CONFIGURATION
775 teardown_env($testenv_name);
780 $cmd =~ s/([\(\)])/\\$1/g;
782 my $envname = $$_[1];
784 my $skipreason = skip($name);
786 $msg_ops->skip_testsuite($envname, $name, $skipreason);
787 $statistics->{SUITES_SKIPPED}++;
791 my $envvars = setup_env($envname);
792 if (not defined($envvars)) {
793 $statistics->{SUITES_SKIPPED}++;
794 $msg_ops->missing_env($name, $envname);
798 run_testsuite($envname, $envvars, $name, $cmd, $i, $suitestotal,
801 if (defined($opt_analyse_cmd)) {
802 system("$opt_analyse_cmd \"$name\"");
805 teardown_env($envname) if ($opt_resetup_env);
811 teardown_env($_) foreach (keys %running_envs);
815 $statistics->{END_TIME} = time();
816 my $duration = ($statistics->{END_TIME}-$statistics->{START_TIME});
818 print "DURATION: $duration seconds\n";
822 # if there were any valgrind failures, show them
823 foreach (<$prefix/valgrind.log*>) {
825 system("grep DWARF2.CFI.reader $_ > /dev/null");
827 print "VALGRIND FAILURE\n";
833 if ($opt_format eq "buildfarm") {
834 print "TEST STATUS: $statistics->{SUITES_FAIL}\n";
837 exit $statistics->{SUITES_FAIL};