Don't leave release trees hanging around
[jelmer/samba4-debian.git] / source / selftest / selftest.pl
1 #!/usr/bin/perl
2 # Bootstrap Samba and run a number of tests against it.
3 # Copyright (C) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
4 # Published under the GNU GPL, v3 or later.
5
6 =pod
7
8 =head1 NAME
9
10 selftest - Samba test runner
11
12 =head1 SYNOPSIS
13
14 selftest --help
15
16 selftest [--srcdir=DIR] [--builddir=DIR] [--target=samba4|samba3|win|kvm] [--socket-wrapper] [--quick] [--exclude=FILE] [--include=FILE] [--one] [--prefix=prefix] [--immediate] [--testlist=FILE] [TESTS]
17
18 =head1 DESCRIPTION
19
20 A simple test runner. TESTS is a regular expression with tests to run.
21
22 =head1 OPTIONS
23
24 =over 4
25
26 =item I<--help>
27
28 Show list of available options.
29
30 =item I<--srcdir=DIR>
31
32 Source directory.
33
34 =item I<--builddir=DIR>
35
36 Build directory.
37
38 =item I<--prefix=DIR>
39
40 Change directory to run tests in. Default is 'st'.
41
42 =item I<--immediate>
43
44 Show errors as soon as they happen rather than at the end of the test run.
45                 
46 =item I<--target samba4|samba3|win|kvm>
47
48 Specify test target against which to run. Default is 'samba4'.
49
50 =item I<--quick>
51
52 Run only a limited number of tests. Intended to run in about 30 seconds on 
53 moderately recent systems.
54                 
55 =item I<--socket-wrapper>
56
57 Use socket wrapper library for communication with server. Only works 
58 when the server is running locally.
59
60 Will prevent TCP and UDP ports being opened on the local host but 
61 (transparently) redirects these calls to use unix domain sockets.
62
63 =item I<--expected-failures>
64
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.
67
68 The format for the file is, one entry per line:
69
70 TESTSUITE-NAME.TEST-NAME
71
72 The reason for a test can also be specified, by adding a hash sign (#) and the reason 
73 after the test name.
74
75 =item I<--exclude>
76
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.
80
81 =item I<--include>
82
83 Specify a file containing a list of tests that should be run. Same format 
84 as the --exclude flag.
85
86 Not includes specified means all tests will be run.
87
88 =item I<--one>
89
90 Abort as soon as one test fails.
91
92 =item I<--testlist>
93
94 Load a list of tests from the specified location.
95
96 =back
97
98 =head1 ENVIRONMENT
99
100 =over 4
101
102 =item I<SMBD_VALGRIND>
103
104 =item I<TORTURE_MAXTIME>
105
106 =item I<VALGRIND>
107
108 =item I<TLS_ENABLED>
109
110 =item I<srcdir>
111
112 =back
113
114 =head1 LICENSE
115
116 selftest is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
117
118 =head1 AUTHOR
119
120 Jelmer Vernooij
121
122 =cut
123
124 use strict;
125
126 use FindBin qw($RealBin $Script);
127 use File::Spec;
128 use Getopt::Long;
129 use POSIX;
130 use Cwd qw(abs_path);
131 use lib "$RealBin";
132 use Subunit qw(parse_results);
133 use SocketWrapper;
134
135 my $opt_help = 0;
136 my $opt_target = "samba4";
137 my $opt_quick = 0;
138 my $opt_socket_wrapper = 0;
139 my $opt_socket_wrapper_pcap = undef;
140 my $opt_socket_wrapper_keep_pcap = undef;
141 my $opt_one = 0;
142 my $opt_immediate = 0;
143 my $opt_expected_failures = undef;
144 my @opt_exclude = ();
145 my @opt_include = ();
146 my $opt_verbose = 0;
147 my $opt_image = undef;
148 my $opt_testenv = 0;
149 my $ldap = undef;
150 my $opt_analyse_cmd = undef;
151 my $opt_resetup_env = undef;
152 my $opt_bindir = undef;
153 my $opt_no_lazy_setup = undef;
154 my $opt_format = "plain";
155 my @testlists = ();
156
157 my $srcdir = ".";
158 my $builddir = ".";
159 my $prefix = "./st";
160
161 my @expected_failures = ();
162 my @includes = ();
163 my @excludes = ();
164
165 my $statistics = {
166         SUITES_FAIL => 0,
167
168         TESTS_UNEXPECTED_OK => 0,
169         TESTS_EXPECTED_OK => 0,
170         TESTS_UNEXPECTED_FAIL => 0,
171         TESTS_EXPECTED_FAIL => 0,
172         TESTS_ERROR => 0,
173         TESTS_SKIP => 0,
174 };
175
176 sub find_in_list($$)
177 {
178         my ($list, $fullname) = @_;
179
180         foreach (@$list) {
181                 if ($fullname =~ /$$_[0]/) {
182                          return ($$_[1]) if ($$_[1]);
183                          return "NO REASON SPECIFIED";
184                 }
185         }
186
187         return undef;
188 }
189
190 sub expecting_failure($)
191 {
192         my ($name) = @_;
193         return find_in_list(\@expected_failures, $name);
194 }
195
196 sub skip($)
197 {
198         my ($name) = @_;
199
200         return find_in_list(\@excludes, $name);
201 }
202
203 sub getlog_env($);
204
205 sub setup_pcap($)
206 {
207         my ($name) = @_;
208
209         return unless ($opt_socket_wrapper_pcap);
210         return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
211
212         my $fname = $name;
213         $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
214
215         my $pcap_file = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
216
217         SocketWrapper::setup_pcap($pcap_file);
218
219         return $pcap_file;
220 }
221
222 sub cleanup_pcap($$$)
223 {
224         my ($pcap_file, $expected_ret, $ret) = @_;
225
226         return unless ($opt_socket_wrapper_pcap);
227         return if ($opt_socket_wrapper_keep_pcap);
228         return unless ($expected_ret == $ret);
229         return unless defined($pcap_file);
230
231         unlink($pcap_file);
232 }
233
234 sub run_testsuite($$$$$$)
235 {
236         my ($envname, $name, $cmd, $i, $totalsuites, $msg_ops) = @_;
237         my $pcap_file = setup_pcap($name);
238
239         $msg_ops->start_test([], $name);
240
241         open(RESULT, "$cmd 2>&1|");
242         my $expected_ret = parse_results(
243                 $msg_ops, $statistics, *RESULT, \&expecting_failure, [$name]);
244
245         my $envlog = getlog_env($envname);
246         $msg_ops->output_msg("ENVLOG: $envlog\n") if ($envlog ne "");
247
248         $msg_ops->output_msg("CMD: $cmd\n");
249
250         my $ret = close(RESULT);
251         $ret = 0 unless $ret == 1;
252
253         if ($ret == 1) {
254                 $msg_ops->end_test([], $name, "success", $expected_ret != $ret, undef);
255         } else {
256                 $msg_ops->end_test([], $name, "failure", $expected_ret != $ret, 
257                                                "Returned $ret");
258         }
259
260         cleanup_pcap($pcap_file, $expected_ret, $ret);
261
262         if (not $opt_socket_wrapper_keep_pcap and 
263                 defined($pcap_file)) {
264                 $msg_ops->output_msg("PCAP FILE: $pcap_file\n");
265         }
266
267         if ($ret != $expected_ret) {
268                 $statistics->{SUITES_FAIL}++;
269                 exit(1) if ($opt_one);
270         }
271
272         return ($ret == $expected_ret);
273 }
274
275 sub ShowHelp()
276 {
277         print "Samba test runner
278 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
279
280 Usage: $Script [OPTIONS] PREFIX
281
282 Generic options:
283  --help                     this help page
284  --target=samba[34]|win|kvm Samba version to target
285  --testlist=FILE                        file to read available tests from
286
287 Paths:
288  --prefix=DIR               prefix to run tests in [st]
289  --srcdir=DIR               source directory [.]
290  --builddir=DIR             output directory [.]
291
292 Target Specific:
293  --socket-wrapper-pcap          save traffic to pcap directories
294  --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that 
295                             failed
296  --socket-wrapper           enable socket wrapper
297  --expected-failures=FILE   specify list of tests that is guaranteed to fail
298
299 Samba4 Specific:
300  --ldap=openldap|fedora-ds     back smbd onto specified ldap server
301
302 Samba3 Specific:
303  --bindir=PATH              path to binaries
304
305 Kvm Specific:
306  --image=PATH               path to KVM image
307
308 Behaviour:
309  --quick                    run quick overall test
310  --one                      abort when the first test fails
311  --immediate                print test output for failed tests during run
312  --verbose                  be verbose
313  --analyse-cmd CMD          command to run after each test
314 ";
315         exit(0);
316 }
317
318 my $result = GetOptions (
319                 'help|h|?' => \$opt_help,
320                 'target=s' => \$opt_target,
321                 'prefix=s' => \$prefix,
322                 'socket-wrapper' => \$opt_socket_wrapper,
323                 'socket-wrapper-pcap' => \$opt_socket_wrapper_pcap,
324                 'socket-wrapper-keep-pcap' => \$opt_socket_wrapper_keep_pcap,
325                 'quick' => \$opt_quick,
326                 'one' => \$opt_one,
327                 'immediate' => \$opt_immediate,
328                 'expected-failures=s' => \$opt_expected_failures,
329                 'exclude=s' => \@opt_exclude,
330                 'include=s' => \@opt_include,
331                 'srcdir=s' => \$srcdir,
332                 'builddir=s' => \$builddir,
333                 'verbose' => \$opt_verbose,
334                 'testenv' => \$opt_testenv,
335                 'ldap:s' => \$ldap,
336                 'analyse-cmd=s' => \$opt_analyse_cmd,
337                 'no-lazy-setup' => \$opt_no_lazy_setup,
338                 'resetup-environment' => \$opt_resetup_env,
339                 'bindir:s' => \$opt_bindir,
340                 'format=s' => \$opt_format,
341                 'image=s' => \$opt_image,
342                 'testlist=s' => \@testlists
343             );
344
345 exit(1) if (not $result);
346
347 ShowHelp() if ($opt_help);
348
349 my $tests = shift;
350
351 # quick hack to disable rpc validation when using valgrind - its way too slow
352 unless (defined($ENV{VALGRIND})) {
353         $ENV{VALIDATE} = "validate";
354         $ENV{MALLOC_CHECK_} = 2;
355 }
356
357 my $old_pwd = "$RealBin/..";
358
359 # Backwards compatibility:
360 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
361         if (defined($ENV{FEDORA_DS_ROOT})) {
362                 $ldap = "fedora-ds";
363         } else {
364                 $ldap = "openldap";
365         }
366 }
367
368 my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
369 if ($ldap) {
370         # LDAP is slow
371         $torture_maxtime *= 2;
372 }
373
374 $prefix =~ s+//+/+;
375 $prefix =~ s+/./+/+;
376 $prefix =~ s+/$++;
377
378 die("using an empty prefix isn't allowed") unless $prefix ne "";
379
380 #Ensure we have the test prefix around
381 mkdir($prefix, 0777) unless -d $prefix;
382
383 my $prefix_abs = abs_path($prefix);
384 my $srcdir_abs = abs_path($srcdir);
385
386 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
387 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
388
389 $ENV{PREFIX} = $prefix;
390 $ENV{KRB5CCNAME} = "$prefix/krb5ticket";
391 $ENV{PREFIX_ABS} = $prefix_abs;
392 $ENV{SRCDIR} = $srcdir;
393 $ENV{SRCDIR_ABS} = $srcdir_abs;
394
395 if (defined($ENV{RUN_FROM_BUILD_FARM}) and 
396         ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
397         $opt_format = "buildfarm";
398 }
399
400 my $tls_enabled = not $opt_quick;
401 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
402 $ENV{LDB_MODULES_PATH} = "$old_pwd/bin/modules/ldb";
403 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
404 if (defined($ENV{PKG_CONFIG_PATH})) {
405         $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
406 } else { 
407         $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
408 }
409 # Required for smbscript:
410 $ENV{PATH} = "$old_pwd/bin:$old_pwd:$ENV{PATH}";
411
412 if ($opt_socket_wrapper_keep_pcap) {
413         # Socket wrapper keep pcap implies socket wrapper pcap
414         $opt_socket_wrapper_pcap = 1;
415 }
416
417 if ($opt_socket_wrapper_pcap) {
418         # Socket wrapper pcap implies socket wrapper
419         $opt_socket_wrapper = 1;
420 }
421
422 my $socket_wrapper_dir;
423 if ($opt_socket_wrapper) {
424         $socket_wrapper_dir = SocketWrapper::setup_dir("$prefix/w", $opt_socket_wrapper_pcap);
425         print "SOCKET_WRAPPER_DIR=$socket_wrapper_dir\n";
426 } else {
427         warn("Not using socket wrapper, but also not running as root. Will not be able to listen on proper ports") unless $< == 0;
428 }
429
430 my $target;
431 my $testenv_default = "none";
432
433 if ($opt_target eq "samba4") {
434         $testenv_default = "member";
435         require target::Samba4;
436         $target = new Samba4($opt_bindir or "$srcdir/bin", $ldap, "$srcdir/setup");
437 } elsif ($opt_target eq "samba3") {
438         if ($opt_socket_wrapper and `$opt_bindir/smbd -b | grep SOCKET_WRAPPER` eq "") {
439                 die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'.  Exiting....");
440         }
441         $testenv_default = "dc";
442         require target::Samba3;
443         $target = new Samba3($opt_bindir);
444 } elsif ($opt_target eq "win") {
445         die("Windows tests will not run with socket wrapper enabled.") 
446                 if ($opt_socket_wrapper);
447         $testenv_default = "dc";
448         require target::Windows;
449         $target = new Windows();
450 } elsif ($opt_target eq "kvm") {
451         die("Kvm tests will not run with socket wrapper enabled.") 
452                 if ($opt_socket_wrapper);
453         require target::Kvm;
454         die("No image specified") unless ($opt_image);
455         $target = new Kvm($opt_image, undef);
456 }
457
458 #
459 # Start a Virtual Distributed Ethernet Switch
460 # Returns the pid of the switch.
461 #
462 sub start_vde_switch($)
463 {
464         my ($path) = @_;
465
466         system("vde_switch --pidfile $path/vde.pid --sock $path/vde.sock --daemon");
467
468         open(PID, "$path/vde.pid");
469         <PID> =~ /([0-9]+)/;
470         my $pid = $1;
471         close(PID);
472
473         return $pid;
474 }
475
476 # Stop a Virtual Distributed Ethernet Switch
477 sub stop_vde_switch($)
478 {
479         my ($pid) = @_;
480         kill 9, $pid;
481 }
482
483 sub read_test_regexes($)
484 {
485         my ($name) = @_;
486         my @ret = ();
487         open(LF, "<$name") or die("unable to read $name: $!");
488         while (<LF>) { 
489                 chomp; 
490                 if (/^(.*?)([ \t]+)\#([\t ]*)(.*?)$/) {
491                         push (@ret, [$1, $4]);
492                 } else {
493                         s/^(.*?)([ \t]+)\#([\t ]*)(.*?)$//;
494                         push (@ret, [$_, undef]); 
495                 }
496         }
497         close(LF);
498         return @ret;
499 }
500
501 if (defined($opt_expected_failures)) {
502         @expected_failures = read_test_regexes($opt_expected_failures);
503 }
504
505 foreach (@opt_exclude) {
506         push (@excludes, read_test_regexes($_));
507 }
508
509 if ($opt_quick) {
510         push (@includes, read_test_regexes("samba4-quick"));
511 }
512
513 foreach (@opt_include) {
514         push (@includes, read_test_regexes($_));
515 }
516
517 my $interfaces = join(',', ("127.0.0.6/8", 
518                             "127.0.0.7/8",
519                             "127.0.0.8/8",
520                             "127.0.0.9/8",
521                             "127.0.0.10/8",
522                             "127.0.0.11/8"));
523
524 my $conffile = "$prefix_abs/client/client.conf";
525
526 sub write_clientconf($$)
527 {
528         my ($conffile, $vars) = @_;
529
530         mkdir("$prefix/client", 0777) unless -d "$prefix/client";
531         
532         if ( -d "$prefix/client/private" ) {
533                 unlink <$prefix/client/private/*>;
534         } else {
535                 mkdir("$prefix/client/private", 0777);
536         }
537
538         open(CF, ">$conffile");
539         print CF "[global]\n";
540         if (defined($ENV{VALGRIND})) {
541                 print CF "\ticonv:native = true\n";
542         } else {
543                 print CF "\ticonv:native = false\n";
544         }
545         print CF "\tnetbios name = client\n";
546         if (defined($vars->{DOMAIN})) {
547                 print CF "\tworkgroup = $vars->{DOMAIN}\n";
548         }
549         if (defined($vars->{REALM})) {
550                 print CF "\trealm = $vars->{REALM}\n";
551         }
552         if (defined($vars->{NCALRPCDIR})) {
553                 print CF "\tncalrpc dir = $vars->{NCALRPCDIR}\n";
554         }
555         if (defined($vars->{PIDDIR})) {
556                 print CF "\tpid directory = $vars->{PIDDIR}\n";
557         }
558         if (defined($vars->{WINBINDD_SOCKET_DIR})) {
559                 print CF "\twinbindd socket directory = $vars->{WINBINDD_SOCKET_DIR}\n";
560         }
561         if ($opt_socket_wrapper) {
562                 print CF "\tinterfaces = $interfaces\n";
563         }
564         print CF "
565         private dir = $prefix_abs/client/private
566         js include = $srcdir_abs/scripting/libjs
567         name resolve order = bcast
568         panic action = $srcdir_abs/script/gdb_backtrace \%PID\% \%PROG\%
569         max xmit = 32K
570         notify:inotify = false
571         ldb:nosync = true
572         system:anonymous = true
573         torture:basedir = $prefix_abs/client
574 #We don't want to pass our self-tests if the PAC code is wrong
575         gensec:require_pac = true
576         modules dir = $ENV{LD_SAMBA_MODULE_PATH}
577 ";
578         close(CF);
579 }
580
581 my @torture_options = ();
582 push (@torture_options, "--configfile=$conffile");
583 # ensure any one smbtorture call doesn't run too long
584 push (@torture_options, "--maximum-runtime=$torture_maxtime");
585 push (@torture_options, "--target=$opt_target");
586 push (@torture_options, "--basedir=$prefix_abs");
587 push (@torture_options, "--option=torture:progress=no") unless ($opt_verbose);
588 push (@torture_options, "--format=subunit");
589 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
590
591 $ENV{TORTURE_OPTIONS} = join(' ', @torture_options);
592 print "OPTIONS $ENV{TORTURE_OPTIONS}\n";
593
594 my @todo = ();
595
596 my $testsdir = "$srcdir/selftest";
597 $ENV{SMB_CONF_PATH} = "$conffile";
598 $ENV{CONFIGURATION} = "--configfile=$conffile";
599
600 my %required_envs = ();
601
602 sub read_testlist($)
603 {
604         my ($filename) = @_;
605
606         my @ret = ();
607         open(IN, $filename) or die("Unable to open $filename: $!");
608
609         while (<IN>) {
610                 if ($_ eq "-- TEST --\n") {
611                         my $name = <IN>;
612                         $name =~ s/\n//g;
613                         my $env = <IN>;
614                         $env =~ s/\n//g;
615                         my $cmdline = <IN>;
616                         $cmdline =~ s/\n//g;
617                         if (not defined($tests) or $name =~ /$tests/) {
618                                 $required_envs{$env} = 1;
619                                 push (@ret, [$name, $env, $cmdline]);
620                         }
621                 } else {
622                         print;
623                 }
624         }
625         close(IN) or die("Error creating recipe");
626         return @ret;
627 }
628
629 if ($#testlists == -1) {
630         die("No testlists specified");
631 }
632
633 my @available = ();
634 foreach my $fn (@testlists) {
635         foreach (read_testlist($fn)) {
636                 my $name = $$_[0];
637                 next if (@includes and not find_in_list(\@includes, $name));
638                 push (@available, $_);
639         }
640 }
641
642 my $msg_ops;
643 if ($opt_format eq "buildfarm") {
644         require output::buildfarm;
645         $msg_ops = new output::buildfarm($statistics);
646 } elsif ($opt_format eq "plain") {
647         require output::plain;
648         $msg_ops = new output::plain("$prefix/summary", $opt_verbose, $opt_immediate, $statistics, $#available+1);
649 } elsif ($opt_format eq "html") {
650         require output::html;
651         mkdir("test-results", 0777);
652         $msg_ops = new output::html("test-results", $statistics);
653 } else {
654         die("Invalid output format '$opt_format'");
655 }
656
657
658 foreach (@available) {
659         my $name = $$_[0];
660         my $skipreason = skip($name);
661         if ($skipreason) {
662                 $msg_ops->skip_testsuite($name, $skipreason);
663         } else {
664                 push(@todo, $_); 
665         }
666 }
667
668 if ($#todo == -1) {
669         print STDERR "No tests to run\n";
670         exit(1);
671         }
672
673 my $suitestotal = $#todo + 1;
674 my $i = 0;
675 $| = 1;
676
677 my %running_envs = ();
678
679 my @exported_envvars = (
680         # domain stuff
681         "DOMAIN",
682         "REALM",
683
684         # domain controller stuff
685         "DC_SERVER",
686         "DC_SERVER_IP",
687         "DC_NETBIOSNAME",
688         "DC_NETBIOSALIAS",
689
690         # server stuff
691         "SERVER",
692         "SERVER_IP",
693         "NETBIOSNAME",
694         "NETBIOSALIAS",
695
696         # user stuff
697         "USERNAME",
698         "PASSWORD",
699         "DC_USERNAME",
700         "DC_PASSWORD",
701
702         # misc stuff
703         "KRB5_CONFIG",
704         "WINBINDD_SOCKET_DIR",
705         "WINBINDD_PRIV_PIPE_DIR"
706 );
707
708 $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub { 
709         my $signame = shift;
710         teardown_env($_) foreach(keys %running_envs);
711         die("Received signal $signame");
712 };
713
714 sub setup_env($)
715 {
716         my ($envname) = @_;
717
718         my $testenv_vars;
719         if ($envname eq "none") {
720                 $testenv_vars = {};
721         } elsif (defined($running_envs{$envname})) {
722                 $testenv_vars = $running_envs{$envname};
723                 if (not $target->check_env($testenv_vars)) {
724                         $testenv_vars = undef;
725                 }
726         } else {
727                 $testenv_vars = $target->setup_env($envname, $prefix);
728         }
729
730         return undef unless defined($testenv_vars);
731
732         $running_envs{$envname} = $testenv_vars;
733
734         SocketWrapper::set_default_iface(6);
735         write_clientconf($conffile, $testenv_vars);
736
737         foreach (@exported_envvars) {
738                 if (defined($testenv_vars->{$_})) {
739                         $ENV{$_} = $testenv_vars->{$_};
740                 } else {
741                         delete $ENV{$_};
742                 }
743         }
744
745         return $testenv_vars;
746 }
747
748 sub exported_envvars_str($)
749 {
750         my ($testenv_vars) = @_;
751         my $out = "";
752
753         foreach (@exported_envvars) {
754                 next unless defined($testenv_vars->{$_});
755                 $out .= $_."=".$testenv_vars->{$_}."\n";
756         }
757
758         return $out;
759 }
760
761 sub getlog_env($)
762 {
763         my ($envname) = @_;
764         return "" if ($envname eq "none");
765         return $target->getlog_env($running_envs{$envname});
766 }
767
768 sub check_env($)
769 {
770         my ($envname) = @_;
771         return 1 if ($envname eq "none");
772         return $target->check_env($running_envs{$envname});
773 }
774
775 sub teardown_env($)
776 {
777         my ($envname) = @_;
778         return if ($envname eq "none");
779         $target->teardown_env($running_envs{$envname});
780         delete $running_envs{$envname};
781 }
782
783 if ($opt_no_lazy_setup) {
784         setup_env($_) foreach (keys %required_envs);
785 }
786
787 if ($opt_testenv) {
788         my $testenv_name = $ENV{SELFTEST_TESTENV};
789         $testenv_name = $testenv_default unless defined($testenv_name);
790
791         my $testenv_vars = setup_env($testenv_name);
792
793         $ENV{PIDDIR} = $testenv_vars->{PIDDIR};
794
795         my $envvarstr = exported_envvars_str($testenv_vars);
796
797         my $term = ($ENV{TERM} or "xterm");
798         system("$term -e 'echo -e \"
799 Welcome to the Samba4 Test environment '$testenv_name'
800
801 This matches the client environment used in make test
802 smbd is pid `cat \$PIDDIR/smbd.pid`
803
804 Some useful environment variables:
805 TORTURE_OPTIONS=\$TORTURE_OPTIONS
806 CONFIGURATION=\$CONFIGURATION
807
808 $envvarstr
809 \" && LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} bash'");
810         teardown_env($testenv_name);
811 } else {
812         foreach (@todo) {
813                 $i++;
814                 my $cmd = $$_[2];
815                 $cmd =~ s/([\(\)])/\\$1/g;
816                 my $name = $$_[0];
817                 my $envname = $$_[1];
818                 
819                 my $envvars = setup_env($envname);
820                 if (not defined($envvars)) {
821                         $msg_ops->skip_testsuite($name, "unable to set up environment $envname");
822                         next;
823                 }
824
825                 run_testsuite($envname, $name, $cmd, $i, $suitestotal, 
826                               $msg_ops);
827
828                 if (defined($opt_analyse_cmd)) {
829                         system("$opt_analyse_cmd \"$name\"");
830                 }
831
832                 teardown_env($envname) if ($opt_resetup_env);
833         }
834 }
835
836 print "\n";
837
838 teardown_env($_) foreach (keys %running_envs);
839
840 $target->stop();
841
842 $msg_ops->summary();
843
844 my $failed = 0;
845
846 # if there were any valgrind failures, show them
847 foreach (<$prefix/valgrind.log*>) {
848         next unless (-s $_);
849         system("grep DWARF2.CFI.reader $_ > /dev/null");
850         if ($? >> 8 == 0) {
851             print "VALGRIND FAILURE\n";
852             $failed++;
853             system("cat $_");
854         }
855 }
856
857 if ($opt_format eq "buildfarm") {
858         print "TEST STATUS: $statistics->{SUITES_FAIL}\n";
859 }
860
861 exit $statistics->{SUITES_FAIL};