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] [--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 candidates are
78 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 Abort as soon as one test fails.
87 Load a list of tests from the specified location.
95 =item I<SMBD_VALGRIND>
97 =item I<TORTURE_MAXTIME>
109 selftest is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
119 use FindBin qw($RealBin $Script);
123 use Cwd qw(abs_path);
125 use Subunit qw(parse_results);
132 my $opt_target = "samba4";
134 my $opt_socket_wrapper = 0;
135 my $opt_socket_wrapper_pcap = undef;
136 my $opt_socket_wrapper_keep_pcap = undef;
138 my $opt_immediate = 0;
139 my $opt_expected_failures = undef;
140 my $opt_skip = undef;
144 my $opt_analyse_cmd = undef;
145 my $opt_resetup_env = undef;
146 my $opt_bindir = undef;
147 my $opt_no_lazy_setup = undef;
148 my $opt_format = "plain";
149 my @opt_testlists = ();
155 my @expected_failures = ();
159 START_TIME => time(),
165 TESTS_UNEXPECTED_OK => 0,
166 TESTS_EXPECTED_OK => 0,
167 TESTS_UNEXPECTED_FAIL => 0,
168 TESTS_EXPECTED_FAIL => 0,
175 my ($list, $fullname) = @_;
178 if ($fullname =~ /$$_[0]/) {
179 return ($$_[1]) if ($$_[1]);
180 return "NO REASON SPECIFIED";
187 sub expecting_failure($)
190 return find_in_list(\@expected_failures, $name);
196 return find_in_list(\@skips, $name);
205 return unless ($opt_socket_wrapper_pcap);
206 return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
208 my $fname = sprintf("t%03u_%s", $state->{INDEX}, $state->{NAME});
209 $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
211 $state->{PCAP_FILE} = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
213 SocketWrapper::setup_pcap($state->{PCAP_FILE});
216 sub cleanup_pcap($$$)
218 my ($state, $expected_ret, $ret) = @_;
220 return unless ($opt_socket_wrapper_pcap);
221 return if ($opt_socket_wrapper_keep_pcap);
222 return unless ($expected_ret == $ret);
223 return unless defined($state->{PCAP_FILE});
225 unlink($state->{PCAP_FILE});
226 $state->{PCAP_FILE} = undef;
229 sub run_testsuite($$$$$$)
231 my ($envname, $name, $cmd, $i, $totalsuites, $msg_ops) = @_;
237 TOTAL => $totalsuites,
241 setup_pcap($msg_state);
243 open(RESULT, "$cmd 2>&1|");
244 $msg_ops->start_testsuite($msg_state);
246 my $expected_ret = parse_results(
247 $msg_ops, $msg_state, $statistics, *RESULT, \&expecting_failure);
249 my $ret = close(RESULT);
251 cleanup_pcap($msg_state, $expected_ret, $ret);
253 $msg_ops->end_testsuite($msg_state, $expected_ret, $ret,
254 getlog_env($msg_state->{ENVNAME}));
256 if (not $opt_socket_wrapper_keep_pcap and
257 defined($msg_state->{PCAP_FILE})) {
258 $msg_ops->output_msg($msg_state,
259 "PCAP FILE: $msg_state->{PCAP_FILE}\n");
262 if ($ret != $expected_ret) {
263 $statistics->{SUITES_FAIL}++;
264 exit(1) if ($opt_one);
266 $statistics->{SUITES_OK}++;
269 return ($ret == $expected_ret);
274 print "Samba test runner
275 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
277 Usage: $Script [OPTIONS] PREFIX
280 --help this help page
281 --target=samba4|samba3|win Samba version to target
282 --testlist=FILE file to read available tests from
285 --prefix=DIR prefix to run tests in [st]
286 --srcdir=DIR source directory [.]
287 --builddir=DIR output directory [.]
290 --socket-wrapper-pcap=DIR save traffic to pcap directories
291 --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that
293 --socket-wrapper enable socket wrapper
294 --expected-failures=FILE specify list of tests that is guaranteed to fail
297 --ldap=openldap|fedora-ds back smbd onto specified ldap server
300 --bindir=PATH path to binaries
303 --quick run quick overall test
304 --one abort when the first test fails
305 --immediate print test output for failed tests during run
307 --analyse-cmd CMD command to run after each test
312 my $result = GetOptions (
313 'help|h|?' => \$opt_help,
314 'target=s' => \$opt_target,
315 'prefix=s' => \$prefix,
316 'socket-wrapper' => \$opt_socket_wrapper,
317 'socket-wrapper-pcap' => \$opt_socket_wrapper_pcap,
318 'socket-wrapper-keep-pcap' => \$opt_socket_wrapper_keep_pcap,
319 'quick' => \$opt_quick,
321 'immediate' => \$opt_immediate,
322 'expected-failures=s' => \$opt_expected_failures,
323 'skip=s' => \$opt_skip,
324 'srcdir=s' => \$srcdir,
325 'builddir=s' => \$builddir,
326 'verbose' => \$opt_verbose,
327 'testenv' => \$opt_testenv,
329 'analyse-cmd=s' => \$opt_analyse_cmd,
330 'no-lazy-setup' => \$opt_no_lazy_setup,
331 'resetup-environment' => \$opt_resetup_env,
332 'bindir:s' => \$opt_bindir,
333 'format=s' => \$opt_format,
334 'testlist=s' => \@opt_testlists
337 exit(1) if (not $result);
339 ShowHelp() if ($opt_help);
343 # quick hack to disable rpc validation when using valgrind - its way too slow
344 unless (defined($ENV{VALGRIND})) {
345 $ENV{VALIDATE} = "validate";
346 $ENV{MALLOC_CHECK_} = 2;
349 my $old_pwd = "$RealBin/..";
351 # Backwards compatibility:
352 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
353 if (defined($ENV{FEDORA_DS_PREFIX})) {
360 my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
363 $torture_maxtime *= 2;
370 die("using an empty prefix isn't allowed") unless $prefix ne "";
372 #Ensure we have the test prefix around
373 mkdir($prefix, 0777) unless -d $prefix;
375 my $prefix_abs = abs_path($prefix);
376 my $srcdir_abs = abs_path($srcdir);
378 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
379 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
381 $ENV{PREFIX} = $prefix;
382 $ENV{PREFIX_ABS} = $prefix_abs;
383 $ENV{SRCDIR} = $srcdir;
384 $ENV{SRCDIR_ABS} = $srcdir_abs;
386 my $tls_enabled = not $opt_quick;
387 if (defined($ENV{RUN_FROM_BUILD_FARM}) and
388 ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
389 $opt_format = "buildfarm";
392 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
393 $ENV{LD_LDB_MODULE_PATH} = "$old_pwd/bin/modules/ldb";
394 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
395 if (defined($ENV{LD_LIBRARY_PATH})) {
396 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared:$ENV{LD_LIBRARY_PATH}";
398 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared";
400 if (defined($ENV{PKG_CONFIG_PATH})) {
401 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
403 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
405 # Required for smbscript:
406 $ENV{PATH} = "$old_pwd/bin:$old_pwd:$ENV{PATH}";
409 if ($opt_socket_wrapper_pcap) {
410 # Socket wrapper pcap implies socket wrapper
411 $opt_socket_wrapper = 1;
414 my $socket_wrapper_dir;
415 if ($opt_socket_wrapper) {
416 $socket_wrapper_dir = SocketWrapper::setup_dir("$prefix/w", $opt_socket_wrapper_pcap);
417 print "SOCKET_WRAPPER_DIR=$socket_wrapper_dir\n";
419 warn("Not using socket wrapper, but also not running as root. Will not be able to listen on proper ports") unless $< == 0;
424 if ($opt_target eq "samba4") {
425 $target = new Samba4($opt_bindir or "$srcdir/bin", $ldap, "$srcdir/setup");
426 } elsif ($opt_target eq "samba3") {
427 if ($opt_socket_wrapper and `$opt_bindir/smbd -b | grep SOCKET_WRAPPER` eq "") {
428 die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....");
431 $target = new Samba3($opt_bindir);
432 } elsif ($opt_target eq "win") {
433 die("Windows tests will not run with socket wrapper enabled.")
434 if ($opt_socket_wrapper);
435 $target = new Windows();
438 sub read_test_regexes($)
442 open(LF, "<$name") or die("unable to read $name: $!");
445 if (/^(.*?)([ \t]+)\#(.*)$/) {
446 push (@ret, [$1, $3]);
448 s/^(.*?)([ \t]+)\#(.*)$//;
449 push (@ret, [$_, undef]);
456 if (defined($opt_expected_failures)) {
457 @expected_failures = read_test_regexes($opt_expected_failures);
460 if (defined($opt_skip)) {
461 @skips = read_test_regexes($opt_skip);
464 my $interfaces = join(',', ("127.0.0.6/8",
471 my $conffile = "$prefix_abs/client/client.conf";
473 sub write_clientconf($$)
475 my ($conffile, $vars) = @_;
477 mkdir("$prefix/client", 0777) unless -d "$prefix/client";
479 if ( -d "$prefix/client/private" ) {
480 unlink <$prefix/client/private/*>;
482 mkdir("$prefix/client/private", 0777);
485 open(CF, ">$conffile");
486 print CF "[global]\n";
487 if (defined($ENV{VALGRIND})) {
488 print CF "\ticonv:native = true\n";
490 print CF "\ticonv:native = false\n";
492 print CF "\tnetbios name = client\n";
493 if (defined($vars->{DOMAIN})) {
494 print CF "\tworkgroup = $vars->{DOMAIN}\n";
496 if (defined($vars->{REALM})) {
497 print CF "\trealm = $vars->{REALM}\n";
499 if (defined($vars->{NCALRPCDIR})) {
500 print CF "\tncalrpc dir = $vars->{NCALRPCDIR}\n";
502 if (defined($vars->{PIDDIR})) {
503 print CF "\tpid directory = $vars->{PIDDIR}\n";
505 if (defined($vars->{WINBINDD_SOCKET_DIR})) {
506 print CF "\twinbindd socket directory = $vars->{WINBINDD_SOCKET_DIR}\n";
509 private dir = $prefix_abs/client/private
510 js include = $srcdir_abs/scripting/libjs
511 name resolve order = bcast
512 interfaces = $interfaces
513 panic action = $srcdir_abs/script/gdb_backtrace \%PID\% \%PROG\%
515 notify:inotify = false
517 system:anonymous = true
518 torture:basedir = $prefix_abs/client
519 #We don't want to pass our self-tests if the PAC code is wrong
520 gensec:require_pac = true
526 my @torture_options = ();
527 push (@torture_options, "--configfile=$conffile");
528 # ensure any one smbtorture call doesn't run too long
529 push (@torture_options, "--maximum-runtime=$torture_maxtime");
530 push (@torture_options, "--target=$opt_target");
531 push (@torture_options, "--basedir=$prefix");
532 push (@torture_options, "--option=torture:progress=no") if ($opt_format eq "buildfarm");
533 push (@torture_options, "--format=subunit");
534 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
536 $ENV{TORTURE_OPTIONS} = join(' ', @torture_options);
537 print "OPTIONS $ENV{TORTURE_OPTIONS}\n";
541 my $testsdir = "$srcdir/selftest";
542 $ENV{SMB_CONF_PATH} = "$conffile";
543 $ENV{CONFIGURATION} = "--configfile=$conffile";
545 my %required_envs = ();
552 open(IN, $filename) or die("Unable to open $filename: $!");
555 if ($_ eq "-- TEST --\n") {
562 if (not defined($tests) or $name =~ /$tests/) {
563 $required_envs{$env} = 1;
564 push (@ret, [$name, $env, $cmdline]);
570 close(IN) or die("Error creating recipe");
575 @todo = read_testlist("$testsdir/tests_quick.sh|");
577 @todo = read_testlist("$testsdir/tests_all.sh|");
580 foreach (@opt_testlists) {
581 push(@todo, read_testlist($_));
584 my $suitestotal = $#todo + 1;
588 my %running_envs = ();
590 my @exported_envvars = (
595 # domain controller stuff
615 "WINBINDD_SOCKET_DIR"
623 if ($envname eq "none") {
625 } elsif (defined($running_envs{$envname})) {
626 $testenv_vars = $running_envs{$envname};
627 if (not $target->check_env($testenv_vars)) {
628 $testenv_vars = undef;
631 $testenv_vars = $target->setup_env($envname, $prefix);
634 return undef unless defined($testenv_vars);
636 SocketWrapper::set_default_iface(6);
637 write_clientconf($conffile, $testenv_vars);
639 foreach (@exported_envvars) {
640 if (defined($testenv_vars->{$_})) {
641 $ENV{$_} = $testenv_vars->{$_};
647 $running_envs{$envname} = $testenv_vars;
648 return $testenv_vars;
651 sub exported_envvars_str($)
653 my ($testenv_vars) = @_;
656 foreach (@exported_envvars) {
657 next unless defined($testenv_vars->{$_});
658 $out .= $_."=".$testenv_vars->{$_}."\n";
667 return "" if ($envname eq "none");
668 return $target->getlog_env($running_envs{$envname});
674 return 1 if ($envname eq "none");
675 return $target->check_env($running_envs{$envname});
681 return if ($envname eq "none");
682 $target->teardown_env($running_envs{$envname});
683 delete $running_envs{$envname};
687 if ($opt_format eq "buildfarm") {
688 require output::buildfarm;
689 $msg_ops = new output::buildfarm();
690 } elsif ($opt_format eq "plain") {
691 require output::plain;
692 $msg_ops = new output::plain($opt_verbose, $opt_immediate, $statistics);
693 } elsif ($opt_format eq "html") {
694 require output::html;
695 mkdir("test-results", 0777);
696 $msg_ops = new output::html("test-results", $statistics);
698 die("Invalid output format '$opt_format'");
701 if ($opt_no_lazy_setup) {
702 setup_env($_) foreach (keys %required_envs);
706 my $testenv_name = $ENV{SELFTEST_TESTENV};
707 $testenv_name = "member" unless defined($testenv_name);
709 my $testenv_vars = setup_env($testenv_name);
711 $ENV{PIDDIR} = $testenv_vars->{PIDDIR};
713 my $envvarstr = exported_envvars_str($testenv_vars);
715 my $term = ($ENV{TERM} or "xterm");
716 system("$term -e 'echo -e \"
717 Welcome to the Samba4 Test environment '$testenv_name'
719 This matches the client environment used in make test
720 smbd is pid `cat \$PIDDIR/smbd.pid`
722 Some useful environment variables:
723 TORTURE_OPTIONS=\$TORTURE_OPTIONS
724 CONFIGURATION=\$CONFIGURATION
728 teardown_env($testenv_name);
733 $cmd =~ s/([\(\)])/\\$1/g;
735 my $envname = $$_[1];
737 my $skipreason = skip($name);
739 $msg_ops->skip_testsuite($envname, $name, $skipreason);
740 $statistics->{SUITES_SKIPPED}++;
744 my $envvars = setup_env($envname);
745 if (not defined($envvars)) {
746 $statistics->{SUITES_SKIPPED}++;
747 $msg_ops->missing_env($name, $envname);
751 run_testsuite($envname, $name, $cmd, $i, $suitestotal, $msg_ops);
753 if (defined($opt_analyse_cmd)) {
754 system("$opt_analyse_cmd \"$name\"");
757 teardown_env($envname) if ($opt_resetup_env);
763 teardown_env($_) foreach (keys %running_envs);
767 $statistics->{END_TIME} = time();
768 my $duration = ($statistics->{END_TIME}-$statistics->{START_TIME});
770 print "DURATION: $duration seconds\n";
774 # if there were any valgrind failures, show them
775 foreach (<$prefix/valgrind.log*>) {
777 system("grep DWARF2.CFI.reader $_ > /dev/null");
779 print "VALGRIND FAILURE\n";
785 if ($opt_format eq "buildfarm") {
786 print "TEST STATUS: $statistics->{SUITES_FAIL}\n";
789 exit $statistics->{SUITES_FAIL};