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 open(RESULT, "$cmd 2>&1|");
255 $msg_ops->start_testsuite($name, $msg_state);
257 my $expected_ret = parse_results(
258 $msg_ops, $msg_state, $statistics, *RESULT, \&expecting_failure);
260 my $ret = close(RESULT);
261 $ret = 0 unless $ret == 1;
263 cleanup_pcap($msg_state, $expected_ret, $ret);
265 $msg_ops->end_testsuite($name, $msg_state, $expected_ret, $ret,
266 getlog_env($msg_state->{ENVNAME}));
268 if (not $opt_socket_wrapper_keep_pcap and
269 defined($msg_state->{PCAP_FILE})) {
270 $msg_ops->output_msg($msg_state,
271 "PCAP FILE: $msg_state->{PCAP_FILE}\n");
274 if ($ret != $expected_ret) {
275 $statistics->{SUITES_FAIL}++;
276 exit(1) if ($opt_one);
278 $statistics->{SUITES_OK}++;
281 return ($ret == $expected_ret);
286 print "Samba test runner
287 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
289 Usage: $Script [OPTIONS] PREFIX
292 --help this help page
293 --target=samba4|samba3|win Samba version to target
294 --testlist=FILE file to read available tests from
297 --prefix=DIR prefix to run tests in [st]
298 --srcdir=DIR source directory [.]
299 --builddir=DIR output directory [.]
302 --socket-wrapper-pcap save traffic to pcap directories
303 --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that
305 --socket-wrapper enable socket wrapper
306 --expected-failures=FILE specify list of tests that is guaranteed to fail
309 --ldap=openldap|fedora-ds back smbd onto specified ldap server
312 --bindir=PATH path to binaries
315 --quick run quick overall test
316 --one abort when the first test fails
317 --immediate print test output for failed tests during run
319 --analyse-cmd CMD command to run after each test
324 my $result = GetOptions (
325 'help|h|?' => \$opt_help,
326 'target=s' => \$opt_target,
327 'prefix=s' => \$prefix,
328 'socket-wrapper' => \$opt_socket_wrapper,
329 'socket-wrapper-pcap' => \$opt_socket_wrapper_pcap,
330 'socket-wrapper-keep-pcap' => \$opt_socket_wrapper_keep_pcap,
331 'quick' => \$opt_quick,
333 'immediate' => \$opt_immediate,
334 'expected-failures=s' => \$opt_expected_failures,
335 'exclude=s' => \@opt_exclude,
336 'include=s' => \@opt_include,
337 'srcdir=s' => \$srcdir,
338 'builddir=s' => \$builddir,
339 'verbose' => \$opt_verbose,
340 'testenv' => \$opt_testenv,
342 'analyse-cmd=s' => \$opt_analyse_cmd,
343 'no-lazy-setup' => \$opt_no_lazy_setup,
344 'resetup-environment' => \$opt_resetup_env,
345 'bindir:s' => \$opt_bindir,
346 'format=s' => \$opt_format,
347 'testlist=s' => \@testlists
350 exit(1) if (not $result);
352 ShowHelp() if ($opt_help);
356 # quick hack to disable rpc validation when using valgrind - its way too slow
357 unless (defined($ENV{VALGRIND})) {
358 $ENV{VALIDATE} = "validate";
359 $ENV{MALLOC_CHECK_} = 2;
362 my $old_pwd = "$RealBin/..";
364 # Backwards compatibility:
365 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
366 if (defined($ENV{FEDORA_DS_PREFIX})) {
373 my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
376 $torture_maxtime *= 2;
383 die("using an empty prefix isn't allowed") unless $prefix ne "";
385 #Ensure we have the test prefix around
386 mkdir($prefix, 0777) unless -d $prefix;
388 my $prefix_abs = abs_path($prefix);
389 my $srcdir_abs = abs_path($srcdir);
391 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
392 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
394 $ENV{PREFIX} = $prefix;
395 $ENV{PREFIX_ABS} = $prefix_abs;
396 $ENV{SRCDIR} = $srcdir;
397 $ENV{SRCDIR_ABS} = $srcdir_abs;
399 if (defined($ENV{RUN_FROM_BUILD_FARM}) and
400 ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
401 $opt_format = "buildfarm";
404 my $tls_enabled = not $opt_quick;
405 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
406 $ENV{LDB_MODULES_PATH} = "$old_pwd/bin/modules/ldb";
407 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
408 if (defined($ENV{LD_LIBRARY_PATH})) {
409 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared:$ENV{LD_LIBRARY_PATH}";
411 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared";
413 if (defined($ENV{PKG_CONFIG_PATH})) {
414 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
416 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
418 # Required for smbscript:
419 $ENV{PATH} = "$old_pwd/bin:$old_pwd:$ENV{PATH}";
421 if ($opt_socket_wrapper_keep_pcap) {
422 # Socket wrapper keep pcap implies socket wrapper pcap
423 $opt_socket_wrapper_pcap = 1;
426 if ($opt_socket_wrapper_pcap) {
427 # Socket wrapper pcap implies socket wrapper
428 $opt_socket_wrapper = 1;
431 my $socket_wrapper_dir;
432 if ($opt_socket_wrapper) {
433 $socket_wrapper_dir = SocketWrapper::setup_dir("$prefix/w", $opt_socket_wrapper_pcap);
434 print "SOCKET_WRAPPER_DIR=$socket_wrapper_dir\n";
436 warn("Not using socket wrapper, but also not running as root. Will not be able to listen on proper ports") unless $< == 0;
440 my $testenv_default = "none";
442 if ($opt_target eq "samba4") {
443 $testenv_default = "member";
444 $target = new Samba4($opt_bindir or "$srcdir/bin", $ldap, "$srcdir/setup");
445 } elsif ($opt_target eq "samba3") {
446 if ($opt_socket_wrapper and `$opt_bindir/smbd -b | grep SOCKET_WRAPPER` eq "") {
447 die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....");
449 $testenv_default = "dc";
450 $target = new Samba3($opt_bindir);
451 } elsif ($opt_target eq "win") {
452 die("Windows tests will not run with socket wrapper enabled.")
453 if ($opt_socket_wrapper);
454 $testenv_default = "dc";
455 $target = new Windows();
458 sub read_test_regexes($)
462 open(LF, "<$name") or die("unable to read $name: $!");
465 if (/^(.*?)([ \t]+)\#([\t ]*)(.*?)$/) {
466 push (@ret, [$1, $4]);
468 s/^(.*?)([ \t]+)\#([\t ]*)(.*?)$//;
469 push (@ret, [$_, undef]);
476 if (defined($opt_expected_failures)) {
477 @expected_failures = read_test_regexes($opt_expected_failures);
480 foreach (@opt_exclude) {
481 push (@excludes, read_test_regexes($_));
485 push (@includes, read_test_regexes("samba4-quick"));
488 foreach (@opt_include) {
489 push (@includes, read_test_regexes($_));
492 my $interfaces = join(',', ("127.0.0.6/8",
499 my $conffile = "$prefix_abs/client/client.conf";
501 sub write_clientconf($$)
503 my ($conffile, $vars) = @_;
505 mkdir("$prefix/client", 0777) unless -d "$prefix/client";
507 if ( -d "$prefix/client/private" ) {
508 unlink <$prefix/client/private/*>;
510 mkdir("$prefix/client/private", 0777);
513 open(CF, ">$conffile");
514 print CF "[global]\n";
515 if (defined($ENV{VALGRIND})) {
516 print CF "\ticonv:native = true\n";
518 print CF "\ticonv:native = false\n";
520 print CF "\tnetbios name = client\n";
521 if (defined($vars->{DOMAIN})) {
522 print CF "\tworkgroup = $vars->{DOMAIN}\n";
524 if (defined($vars->{REALM})) {
525 print CF "\trealm = $vars->{REALM}\n";
527 if (defined($vars->{NCALRPCDIR})) {
528 print CF "\tncalrpc dir = $vars->{NCALRPCDIR}\n";
530 if (defined($vars->{PIDDIR})) {
531 print CF "\tpid directory = $vars->{PIDDIR}\n";
533 if (defined($vars->{WINBINDD_SOCKET_DIR})) {
534 print CF "\twinbindd socket directory = $vars->{WINBINDD_SOCKET_DIR}\n";
537 private dir = $prefix_abs/client/private
538 js include = $srcdir_abs/scripting/libjs
539 name resolve order = bcast
540 interfaces = $interfaces
541 panic action = $srcdir_abs/script/gdb_backtrace \%PID\% \%PROG\%
543 notify:inotify = false
545 system:anonymous = true
546 torture:basedir = $prefix_abs/client
547 #We don't want to pass our self-tests if the PAC code is wrong
548 gensec:require_pac = true
549 modules dir = $ENV{LD_SAMBA_MODULE_PATH}
555 my @torture_options = ();
556 push (@torture_options, "--configfile=$conffile");
557 # ensure any one smbtorture call doesn't run too long
558 push (@torture_options, "--maximum-runtime=$torture_maxtime");
559 push (@torture_options, "--target=$opt_target");
560 push (@torture_options, "--basedir=$prefix_abs");
561 push (@torture_options, "--option=torture:progress=no") if ($opt_format eq "buildfarm");
562 push (@torture_options, "--format=subunit");
563 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
565 $ENV{TORTURE_OPTIONS} = join(' ', @torture_options);
566 print "OPTIONS $ENV{TORTURE_OPTIONS}\n";
570 my $testsdir = "$srcdir/selftest";
571 $ENV{SMB_CONF_PATH} = "$conffile";
572 $ENV{CONFIGURATION} = "--configfile=$conffile";
574 my %required_envs = ();
581 open(IN, $filename) or die("Unable to open $filename: $!");
584 if ($_ eq "-- TEST --\n") {
591 if (not defined($tests) or $name =~ /$tests/) {
592 $required_envs{$env} = 1;
593 push (@ret, [$name, $env, $cmdline]);
599 close(IN) or die("Error creating recipe");
603 if ($#testlists == -1) {
604 die("No testlists specified");
608 if ($opt_format eq "buildfarm") {
609 require output::buildfarm;
610 $msg_ops = new output::buildfarm($statistics);
611 } elsif ($opt_format eq "plain") {
612 require output::plain;
613 $msg_ops = new output::plain("$prefix/summary", $opt_verbose, $opt_immediate, $statistics);
614 } elsif ($opt_format eq "html") {
615 require output::html;
616 mkdir("test-results", 0777);
617 $msg_ops = new output::html("test-results", $statistics);
619 die("Invalid output format '$opt_format'");
622 foreach my $fn (@testlists) {
623 foreach (read_testlist($fn)) {
625 next if (@includes and not find_in_list(\@includes, $name));
626 my $skipreason = skip($name);
628 $msg_ops->skip_testsuite($name, $skipreason);
629 $statistics->{SUITES_SKIPPED}++;
637 print STDERR "No tests to run\n";
641 my $suitestotal = $#todo + 1;
645 my %running_envs = ();
647 my @exported_envvars = (
652 # domain controller stuff
672 "WINBINDD_SOCKET_DIR",
673 "WINBINDD_PRIV_PIPE_DIR"
676 $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
678 teardown_env($_) foreach(keys %running_envs);
679 die("Received signal $signame");
687 if ($envname eq "none") {
689 } elsif (defined($running_envs{$envname})) {
690 $testenv_vars = $running_envs{$envname};
691 if (not $target->check_env($testenv_vars)) {
692 $testenv_vars = undef;
695 $testenv_vars = $target->setup_env($envname, $prefix);
698 return undef unless defined($testenv_vars);
700 $running_envs{$envname} = $testenv_vars;
702 SocketWrapper::set_default_iface(6);
703 write_clientconf($conffile, $testenv_vars);
705 foreach (@exported_envvars) {
706 if (defined($testenv_vars->{$_})) {
707 $ENV{$_} = $testenv_vars->{$_};
713 return $testenv_vars;
716 sub exported_envvars_str($)
718 my ($testenv_vars) = @_;
721 foreach (@exported_envvars) {
722 next unless defined($testenv_vars->{$_});
723 $out .= $_."=".$testenv_vars->{$_}."\n";
732 return "" if ($envname eq "none");
733 return $target->getlog_env($running_envs{$envname});
739 return 1 if ($envname eq "none");
740 return $target->check_env($running_envs{$envname});
746 return if ($envname eq "none");
747 $target->teardown_env($running_envs{$envname});
748 delete $running_envs{$envname};
752 if ($opt_no_lazy_setup) {
753 setup_env($_) foreach (keys %required_envs);
757 my $testenv_name = $ENV{SELFTEST_TESTENV};
758 $testenv_name = $testenv_default unless defined($testenv_name);
760 my $testenv_vars = setup_env($testenv_name);
762 $ENV{PIDDIR} = $testenv_vars->{PIDDIR};
764 my $envvarstr = exported_envvars_str($testenv_vars);
766 my $term = ($ENV{TERM} or "xterm");
767 system("$term -e 'echo -e \"
768 Welcome to the Samba4 Test environment '$testenv_name'
770 This matches the client environment used in make test
771 smbd is pid `cat \$PIDDIR/smbd.pid`
773 Some useful environment variables:
774 TORTURE_OPTIONS=\$TORTURE_OPTIONS
775 CONFIGURATION=\$CONFIGURATION
779 teardown_env($testenv_name);
784 $cmd =~ s/([\(\)])/\\$1/g;
786 my $envname = $$_[1];
788 my $envvars = setup_env($envname);
789 if (not defined($envvars)) {
790 $statistics->{SUITES_SKIPPED}++;
791 $msg_ops->skip_testsuite($name, "unable to set up environment $envname");
795 run_testsuite($envname, $envvars, $name, $cmd, $i, $suitestotal,
798 if (defined($opt_analyse_cmd)) {
799 system("$opt_analyse_cmd \"$name\"");
802 teardown_env($envname) if ($opt_resetup_env);
808 teardown_env($_) foreach (keys %running_envs);
812 $statistics->{END_TIME} = time();
813 my $duration = ($statistics->{END_TIME}-$statistics->{START_TIME});
815 print "DURATION: $duration seconds\n";
819 # if there were any valgrind failures, show them
820 foreach (<$prefix/valgrind.log*>) {
822 system("grep DWARF2.CFI.reader $_ > /dev/null");
824 print "VALGRIND FAILURE\n";
830 if ($opt_format eq "buildfarm") {
831 print "TEST STATUS: $statistics->{SUITES_FAIL}\n";
834 exit $statistics->{SUITES_FAIL};