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] [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
74 Specify a file containing a list of tests that should be skipped. Possible candidates are
75 tests that segfault the server, flip or don't end.
79 Abort as soon as one test fails.
87 =item I<SMBD_VALGRIND>
89 =item I<TORTURE_MAXTIME>
101 selftest is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
111 use FindBin qw($RealBin $Script);
115 use Cwd qw(abs_path);
117 use Subunit qw(parse_results);
124 my $opt_target = "samba4";
126 my $opt_socket_wrapper = 0;
127 my $opt_socket_wrapper_pcap = undef;
128 my $opt_socket_wrapper_keep_pcap = undef;
130 my $opt_immediate = 0;
131 my $opt_expected_failures = undef;
132 my $opt_skip = undef;
136 my $opt_analyse_cmd = undef;
137 my $opt_resetup_env = undef;
138 my $opt_bindir = undef;
139 my $opt_no_lazy_setup = undef;
140 my $opt_format = "plain";
141 my @opt_testlists = ();
147 my @expected_failures = ();
151 START_TIME => time(),
157 TESTS_UNEXPECTED_OK => 0,
158 TESTS_EXPECTED_OK => 0,
159 TESTS_UNEXPECTED_FAIL => 0,
160 TESTS_EXPECTED_FAIL => 0,
167 my ($list, $fullname) = @_;
170 if ($fullname =~ /$$_[0]/) {
171 return ($$_[1]) if ($$_[1]);
172 return "NO REASON SPECIFIED";
179 sub expecting_failure($)
182 return find_in_list(\@expected_failures, $name);
188 return find_in_list(\@skips, $name);
197 return unless ($opt_socket_wrapper_pcap);
198 return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
200 my $fname = sprintf("t%03u_%s", $state->{INDEX}, $state->{NAME});
201 $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
203 $state->{PCAP_FILE} = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
205 SocketWrapper::setup_pcap($state->{PCAP_FILE});
208 sub cleanup_pcap($$$)
210 my ($state, $expected_ret, $ret) = @_;
212 return unless ($opt_socket_wrapper_pcap);
213 return if ($opt_socket_wrapper_keep_pcap);
214 return unless ($expected_ret == $ret);
215 return unless defined($state->{PCAP_FILE});
217 unlink($state->{PCAP_FILE});
218 $state->{PCAP_FILE} = undef;
221 sub run_testsuite($$$$$$)
223 my ($envname, $name, $cmd, $i, $totalsuites, $msg_ops) = @_;
229 TOTAL => $totalsuites,
233 setup_pcap($msg_state);
235 open(RESULT, "$cmd 2>&1|");
236 $msg_ops->start_testsuite($msg_state);
238 my $expected_ret = parse_results(
239 $msg_ops, $msg_state, $statistics, *RESULT, \&expecting_failure);
241 my $ret = close(RESULT);
243 cleanup_pcap($msg_state, $expected_ret, $ret);
245 $msg_ops->end_testsuite($msg_state, $expected_ret, $ret,
246 getlog_env($msg_state->{ENVNAME}));
248 if (not $opt_socket_wrapper_keep_pcap and
249 defined($msg_state->{PCAP_FILE})) {
250 $msg_ops->output_msg($msg_state,
251 "PCAP FILE: $msg_state->{PCAP_FILE}\n");
254 if ($ret != $expected_ret) {
255 $statistics->{SUITES_FAIL}++;
256 exit(1) if ($opt_one);
258 $statistics->{SUITES_OK}++;
261 return ($ret == $expected_ret);
266 print "Samba test runner
267 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
269 Usage: $Script [OPTIONS] PREFIX
272 --help this help page
273 --target=samba4|samba3|win Samba version to target
274 --testlist=FILE file to read available tests from
277 --prefix=DIR prefix to run tests in [st]
278 --srcdir=DIR source directory [.]
279 --builddir=DIR output directory [.]
282 --socket-wrapper-pcap=DIR save traffic to pcap directories
283 --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that
285 --socket-wrapper enable socket wrapper
286 --expected-failures=FILE specify list of tests that is guaranteed to fail
289 --ldap=openldap|fedora-ds back smbd onto specified ldap server
292 --bindir=PATH path to binaries
295 --quick run quick overall test
296 --one abort when the first test fails
297 --immediate print test output for failed tests during run
299 --analyse-cmd CMD command to run after each test
304 my $result = GetOptions (
305 'help|h|?' => \$opt_help,
306 'target=s' => \$opt_target,
307 'prefix=s' => \$prefix,
308 'socket-wrapper' => \$opt_socket_wrapper,
309 'socket-wrapper-pcap' => \$opt_socket_wrapper_pcap,
310 'socket-wrapper-keep-pcap' => \$opt_socket_wrapper_keep_pcap,
311 'quick' => \$opt_quick,
313 'immediate' => \$opt_immediate,
314 'expected-failures=s' => \$opt_expected_failures,
315 'skip=s' => \$opt_skip,
316 'srcdir=s' => \$srcdir,
317 'builddir=s' => \$builddir,
318 'verbose' => \$opt_verbose,
319 'testenv' => \$opt_testenv,
321 'analyse-cmd=s' => \$opt_analyse_cmd,
322 'no-lazy-setup' => \$opt_no_lazy_setup,
323 'resetup-environment' => \$opt_resetup_env,
324 'bindir:s' => \$opt_bindir,
325 'format=s' => \$opt_format,
326 'testlist=s' => \@opt_testlists
329 exit(1) if (not $result);
331 ShowHelp() if ($opt_help);
335 # quick hack to disable rpc validation when using valgrind - its way too slow
336 unless (defined($ENV{VALGRIND})) {
337 $ENV{VALIDATE} = "validate";
338 $ENV{MALLOC_CHECK_} = 2;
341 my $old_pwd = "$RealBin/..";
343 # Backwards compatibility:
344 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
345 if (defined($ENV{FEDORA_DS_PREFIX})) {
352 my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
355 $torture_maxtime *= 2;
362 die("using an empty prefix isn't allowed") unless $prefix ne "";
364 #Ensure we have the test prefix around
365 mkdir($prefix, 0777) unless -d $prefix;
367 my $prefix_abs = abs_path($prefix);
368 my $srcdir_abs = abs_path($srcdir);
370 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
371 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
373 $ENV{PREFIX} = $prefix;
374 $ENV{PREFIX_ABS} = $prefix_abs;
375 $ENV{SRCDIR} = $srcdir;
376 $ENV{SRCDIR_ABS} = $srcdir_abs;
378 my $tls_enabled = not $opt_quick;
379 if (defined($ENV{RUN_FROM_BUILD_FARM}) and
380 ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
381 $opt_format = "buildfarm";
384 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
385 $ENV{LD_LDB_MODULE_PATH} = "$old_pwd/bin/modules/ldb";
386 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
387 if (defined($ENV{LD_LIBRARY_PATH})) {
388 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared:$ENV{LD_LIBRARY_PATH}";
390 $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared";
392 if (defined($ENV{PKG_CONFIG_PATH})) {
393 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
395 $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
397 # Required for smbscript:
398 $ENV{PATH} = "$old_pwd/bin:$old_pwd:$ENV{PATH}";
401 if ($opt_socket_wrapper_pcap) {
402 # Socket wrapper pcap implies socket wrapper
403 $opt_socket_wrapper = 1;
406 my $socket_wrapper_dir;
407 if ($opt_socket_wrapper) {
408 $socket_wrapper_dir = SocketWrapper::setup_dir("$prefix/w", $opt_socket_wrapper_pcap);
409 print "SOCKET_WRAPPER_DIR=$socket_wrapper_dir\n";
411 warn("Not using socket wrapper, but also not running as root. Will not be able to listen on proper ports") unless $< == 0;
416 if ($opt_target eq "samba4") {
417 $target = new Samba4($opt_bindir or "$srcdir/bin", $ldap, "$srcdir/setup");
418 } elsif ($opt_target eq "samba3") {
419 if ($opt_socket_wrapper and `$opt_bindir/smbd -b | grep SOCKET_WRAPPER` eq "") {
420 die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....");
423 $target = new Samba3($opt_bindir);
424 } elsif ($opt_target eq "win") {
425 die("Windows tests will not run with socket wrapper enabled.")
426 if ($opt_socket_wrapper);
427 $target = new Windows();
430 sub read_test_regexes($)
434 open(LF, "<$name") or die("unable to read $name: $!");
437 if (/^(.*?)([ \t]+)\#(.*)$/) {
438 push (@ret, [$1, $3]);
440 s/^(.*?)([ \t]+)\#(.*)$//;
441 push (@ret, [$_, undef]);
448 if (defined($opt_expected_failures)) {
449 @expected_failures = read_test_regexes($opt_expected_failures);
452 if (defined($opt_skip)) {
453 @skips = read_test_regexes($opt_skip);
456 my $interfaces = join(',', ("127.0.0.6/8",
463 my $conffile = "$prefix_abs/client/client.conf";
465 sub write_clientconf($$)
467 my ($conffile, $vars) = @_;
469 mkdir("$prefix/client", 0777) unless -d "$prefix/client";
471 if ( -d "$prefix/client/private" ) {
472 unlink <$prefix/client/private/*>;
474 mkdir("$prefix/client/private", 0777);
477 open(CF, ">$conffile");
478 print CF "[global]\n";
479 if (defined($ENV{VALGRIND})) {
480 print CF "\ticonv:native = true\n";
482 print CF "\ticonv:native = false\n";
484 print CF "\tnetbios name = client\n";
485 if (defined($vars->{DOMAIN})) {
486 print CF "\tworkgroup = $vars->{DOMAIN}\n";
488 if (defined($vars->{REALM})) {
489 print CF "\trealm = $vars->{REALM}\n";
491 if (defined($vars->{NCALRPCDIR})) {
492 print CF "\tncalrpc dir = $vars->{NCALRPCDIR}\n";
494 if (defined($vars->{PIDDIR})) {
495 print CF "\tpid directory = $vars->{PIDDIR}\n";
497 if (defined($vars->{WINBINDD_SOCKET_DIR})) {
498 print CF "\twinbindd socket directory = $vars->{WINBINDD_SOCKET_DIR}\n";
501 private dir = $prefix_abs/client/private
502 js include = $srcdir_abs/scripting/libjs
503 name resolve order = bcast
504 interfaces = $interfaces
505 panic action = $srcdir_abs/script/gdb_backtrace \%PID\% \%PROG\%
507 notify:inotify = false
509 system:anonymous = true
510 torture:basedir = $prefix_abs/client
511 #We don't want to pass our self-tests if the PAC code is wrong
512 gensec:require_pac = true
518 my @torture_options = ();
519 push (@torture_options, "--configfile=$conffile");
520 # ensure any one smbtorture call doesn't run too long
521 push (@torture_options, "--maximum-runtime=$torture_maxtime");
522 push (@torture_options, "--target=$opt_target");
523 push (@torture_options, "--basedir=$prefix");
524 push (@torture_options, "--option=torture:progress=no") if ($opt_format eq "buildfarm");
525 push (@torture_options, "--format=subunit");
526 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
528 $ENV{TORTURE_OPTIONS} = join(' ', @torture_options);
529 print "OPTIONS $ENV{TORTURE_OPTIONS}\n";
533 my $testsdir = "$srcdir/selftest";
534 $ENV{SMB_CONF_PATH} = "$conffile";
535 $ENV{CONFIGURATION} = "--configfile=$conffile";
537 my %required_envs = ();
544 open(IN, $filename) or die("Unable to open $filename: $!");
547 if ($_ eq "-- TEST --\n") {
554 if (not defined($tests) or $name =~ /$tests/) {
555 $required_envs{$env} = 1;
556 push (@ret, [$name, $env, $cmdline]);
562 close(IN) or die("Error creating recipe");
567 @todo = read_testlist("$testsdir/tests_quick.sh|");
569 @todo = read_testlist("$testsdir/tests_all.sh|");
572 foreach (@opt_testlists) {
573 push(@todo, read_testlist($_));
576 my $suitestotal = $#todo + 1;
580 my %running_envs = ();
582 my @exported_envvars = (
587 # domain controller stuff
607 "WINBINDD_SOCKET_DIR"
615 if ($envname eq "none") {
617 } elsif (defined($running_envs{$envname})) {
618 $testenv_vars = $running_envs{$envname};
619 if (not $target->check_env($testenv_vars)) {
620 $testenv_vars = undef;
623 $testenv_vars = $target->setup_env($envname, $prefix);
626 return undef unless defined($testenv_vars);
628 SocketWrapper::set_default_iface(6);
629 write_clientconf($conffile, $testenv_vars);
631 foreach (@exported_envvars) {
632 if (defined($testenv_vars->{$_})) {
633 $ENV{$_} = $testenv_vars->{$_};
639 $running_envs{$envname} = $testenv_vars;
640 return $testenv_vars;
643 sub exported_envvars_str($)
645 my ($testenv_vars) = @_;
648 foreach (@exported_envvars) {
649 next unless defined($testenv_vars->{$_});
650 $out .= $_."=".$testenv_vars->{$_}."\n";
659 return "" if ($envname eq "none");
660 return $target->getlog_env($running_envs{$envname});
666 return 1 if ($envname eq "none");
667 return $target->check_env($running_envs{$envname});
673 return if ($envname eq "none");
674 $target->teardown_env($running_envs{$envname});
675 delete $running_envs{$envname};
679 if ($opt_format eq "buildfarm") {
680 require output::buildfarm;
681 $msg_ops = new output::buildfarm();
682 } elsif ($opt_format eq "plain") {
683 require output::plain;
684 $msg_ops = new output::plain($opt_verbose, $opt_immediate, $statistics);
685 } elsif ($opt_format eq "html") {
686 require output::html;
687 mkdir("test-results", 0777);
688 $msg_ops = new output::html("test-results", $statistics);
690 die("Invalid output format '$opt_format'");
693 if ($opt_no_lazy_setup) {
694 setup_env($_) foreach (keys %required_envs);
698 my $testenv_name = $ENV{SELFTEST_TESTENV};
699 $testenv_name = "member" unless defined($testenv_name);
701 my $testenv_vars = setup_env($testenv_name);
703 $ENV{PIDDIR} = $testenv_vars->{PIDDIR};
705 my $envvarstr = exported_envvars_str($testenv_vars);
707 my $term = ($ENV{TERM} or "xterm");
708 system("$term -e 'echo -e \"
709 Welcome to the Samba4 Test environment '$testenv_name'
711 This matches the client environment used in make test
712 smbd is pid `cat \$PIDDIR/smbd.pid`
714 Some useful environment variables:
715 TORTURE_OPTIONS=\$TORTURE_OPTIONS
716 CONFIGURATION=\$CONFIGURATION
720 teardown_env($testenv_name);
725 $cmd =~ s/([\(\)])/\\$1/g;
727 my $envname = $$_[1];
729 my $skipreason = skip($name);
731 $msg_ops->skip_testsuite($envname, $name, $skipreason);
732 $statistics->{SUITES_SKIPPED}++;
736 my $envvars = setup_env($envname);
737 if (not defined($envvars)) {
738 $statistics->{SUITES_SKIPPED}++;
739 $msg_ops->missing_env($name, $envname);
743 run_testsuite($envname, $name, $cmd, $i, $suitestotal, $msg_ops);
745 if (defined($opt_analyse_cmd)) {
746 system("$opt_analyse_cmd \"$name\"");
749 teardown_env($envname) if ($opt_resetup_env);
755 teardown_env($_) foreach (keys %running_envs);
759 $statistics->{END_TIME} = time();
760 my $duration = ($statistics->{END_TIME}-$statistics->{START_TIME});
762 print "DURATION: $duration seconds\n";
766 # if there were any valgrind failures, show them
767 foreach (<$prefix/valgrind.log*>) {
769 system("grep DWARF2.CFI.reader $_ > /dev/null");
771 print "VALGRIND FAILURE\n";
777 if ($opt_format eq "buildfarm") {
778 print "TEST STATUS: $statistics->{SUITES_FAIL}\n";
781 exit $statistics->{SUITES_FAIL};