r24741: More use of the torture API.
[gd/samba-autobuild/.git] / source4 / selftest / selftest.pl
1 #!/usr/bin/perl
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.
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] [--socket-wrapper] [--quick] [--one] [--prefix=prefix] [--immediate] [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>
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 =item I<--skip>
73
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.
76
77 =item I<--one>
78
79 Abort as soon as one test fails.
80
81 =back
82
83 =head1 ENVIRONMENT
84
85 =over 4
86
87 =item I<SMBD_VALGRIND>
88
89 =item I<TORTURE_MAXTIME>
90
91 =item I<VALGRIND>
92
93 =item I<TLS_ENABLED>
94
95 =item I<srcdir>
96
97 =back
98
99 =head1 LICENSE
100
101 selftest is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
102
103 =head1 AUTHOR
104
105 Jelmer Vernooij
106
107 =cut
108
109 use strict;
110
111 use FindBin qw($RealBin $Script);
112 use File::Spec;
113 use Getopt::Long;
114 use POSIX;
115 use Cwd qw(abs_path);
116 use lib "$RealBin";
117 use Subunit qw(parse_results);
118 use env::Samba3;
119 use env::Samba4;
120 use env::Windows;
121 use SocketWrapper;
122
123 my $opt_help = 0;
124 my $opt_target = "samba4";
125 my $opt_quick = 0;
126 my $opt_socket_wrapper = 0;
127 my $opt_socket_wrapper_pcap = undef;
128 my $opt_socket_wrapper_keep_pcap = undef;
129 my $opt_one = 0;
130 my $opt_immediate = 0;
131 my $opt_expected_failures = undef;
132 my $opt_skip = undef;
133 my $opt_verbose = 0;
134 my $opt_testenv = 0;
135 my $ldap = 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
142 my $srcdir = ".";
143 my $builddir = ".";
144 my $prefix = "./st";
145
146 my @expected_failures = ();
147 my @skips = ();
148
149 my $statistics = {
150         START_TIME => time(),
151
152         SUITES_FAIL => 0,
153         SUITES_OK => 0,
154         SUITES_SKIPPED => 0,
155
156         TESTS_UNEXPECTED_OK => 0,
157         TESTS_EXPECTED_OK => 0,
158         TESTS_UNEXPECTED_FAIL => 0,
159         TESTS_EXPECTED_FAIL => 0,
160         TESTS_ERROR => 0,
161         TESTS_SKIP => 0,
162 };
163
164 sub expecting_failure($)
165 {
166         my $fullname = shift;
167
168         foreach (@expected_failures) {
169                 return 1 if ($fullname =~ /$_/);
170         }
171
172         return 0;
173 }
174
175 sub skip($)
176 {
177         my $fullname = shift;
178
179         foreach (@skips) {
180                 return 1 if ($fullname =~ /$_/);
181         }
182
183         return 0;
184 }
185
186 sub getlog_env($);
187
188 sub setup_pcap($)
189 {
190         my ($state) = @_;
191
192         return unless ($opt_socket_wrapper_pcap);
193         return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
194
195         my $fname = sprintf("t%03u_%s", $state->{INDEX}, $state->{NAME});
196         $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
197
198         $state->{PCAP_FILE} = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
199
200         SocketWrapper::setup_pcap($state->{PCAP_FILE});
201 }
202
203 sub cleanup_pcap($$$)
204 {
205         my ($state, $expected_ret, $ret) = @_;
206
207         return unless ($opt_socket_wrapper_pcap);
208         return if ($opt_socket_wrapper_keep_pcap);
209         return unless ($expected_ret == $ret);
210         return unless defined($state->{PCAP_FILE});
211
212         unlink($state->{PCAP_FILE});
213         $state->{PCAP_FILE} = undef;
214 }
215
216 sub run_testsuite($$$$$$)
217 {
218         my ($envname, $name, $cmd, $i, $totalsuites, $msg_ops) = @_;
219         my $msg_state = {
220                 ENVNAME => $envname,
221                 NAME    => $name,
222                 CMD     => $cmd,
223                 INDEX   => $i,
224                 TOTAL   => $totalsuites,
225                 START_TIME      => time()
226         };
227
228         setup_pcap($msg_state);
229
230         open(RESULT, "$cmd 2>&1|");
231         $msg_ops->start_testsuite($msg_state);
232
233         my $expected_ret = parse_results(
234                 $msg_ops, $msg_state, $statistics, *RESULT, \&expecting_failure);
235
236         my $ret = close(RESULT);
237
238         cleanup_pcap($msg_state, $expected_ret, $ret);
239
240         $msg_ops->end_testsuite($msg_state, $expected_ret, $ret,
241                                                         getlog_env($msg_state->{ENVNAME}));
242
243         if (not $opt_socket_wrapper_keep_pcap and 
244                 defined($msg_state->{PCAP_FILE})) {
245                 $msg_ops->output_msg($msg_state, 
246                         "PCAP FILE: $msg_state->{PCAP_FILE}\n");
247         }
248
249         if ($ret != $expected_ret) {
250                 $statistics->{SUITES_FAIL}++;
251                 exit(1) if ($opt_one);
252         } else {
253                 $statistics->{SUITES_OK}++;
254         }
255
256         return ($ret == $expected_ret);
257 }
258
259 sub ShowHelp()
260 {
261         print "Samba test runner
262 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
263
264 Usage: $Script [OPTIONS] PREFIX
265
266 Generic options:
267  --help                     this help page
268  --target=samba4|samba3|win Samba version to target
269
270 Paths:
271  --prefix=DIR               prefix to run tests in [st]
272  --srcdir=DIR               source directory [.]
273  --builddir=DIR             output directory [.]
274
275 Target Specific:
276  --socket-wrapper-pcap=DIR      save traffic to pcap directories
277  --socket-wrapper-keep-pcap keep all pcap files, not just those for tests that 
278                             failed
279  --socket-wrapper           enable socket wrapper
280  --expected-failures=FILE   specify list of tests that is guaranteed to fail
281
282 Samba4 Specific:
283  --ldap=openldap|fedora-ds     back smbd onto specified ldap server
284
285 Samba3 Specific:
286  --bindir=PATH              path to binaries
287
288 Behaviour:
289  --quick                    run quick overall test
290  --one                      abort when the first test fails
291  --immediate                print test output for failed tests during run
292  --verbose                  be verbose
293  --analyse-cmd CMD          command to run after each test
294 ";
295         exit(0);
296 }
297
298 my $result = GetOptions (
299                 'help|h|?' => \$opt_help,
300                 'target=s' => \$opt_target,
301                 'prefix=s' => \$prefix,
302                 'socket-wrapper' => \$opt_socket_wrapper,
303                 'socket-wrapper-pcap' => \$opt_socket_wrapper_pcap,
304                 'socket-wrapper-keep-pcap' => \$opt_socket_wrapper_keep_pcap,
305                 'quick' => \$opt_quick,
306                 'one' => \$opt_one,
307                 'immediate' => \$opt_immediate,
308                 'expected-failures=s' => \$opt_expected_failures,
309                 'skip=s' => \$opt_skip,
310                 'srcdir=s' => \$srcdir,
311                 'builddir=s' => \$builddir,
312                 'verbose' => \$opt_verbose,
313                 'testenv' => \$opt_testenv,
314                 'ldap:s' => \$ldap,
315                 'analyse-cmd=s' => \$opt_analyse_cmd,
316                 'no-lazy-setup' => \$opt_no_lazy_setup,
317                 'resetup-environment' => \$opt_resetup_env,
318                 'bindir:s' => \$opt_bindir,
319                 'format=s' => \$opt_format,
320             );
321
322 exit(1) if (not $result);
323
324 ShowHelp() if ($opt_help);
325
326 my $tests = shift;
327
328 # quick hack to disable rpc validation when using valgrind - its way too slow
329 unless (defined($ENV{VALGRIND})) {
330         $ENV{VALIDATE} = "validate";
331         $ENV{MALLOC_CHECK_} = 2;
332 }
333
334 my $old_pwd = "$RealBin/..";
335
336 # Backwards compatibility:
337 if (defined($ENV{TEST_LDAP}) and $ENV{TEST_LDAP} eq "yes") {
338         if (defined($ENV{FEDORA_DS_PREFIX})) {
339                 $ldap = "fedora-ds";
340         } else {
341                 $ldap = "openldap";
342         }
343 }
344
345 my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
346 if ($ldap) {
347         # LDAP is slow
348         $torture_maxtime *= 2;
349 }
350
351 $prefix =~ s+//+/+;
352 $prefix =~ s+/./+/+;
353 $prefix =~ s+/$++;
354
355 die("using an empty prefix isn't allowed") unless $prefix ne "";
356
357 #Ensure we have the test prefix around
358 mkdir($prefix, 0777) unless -d $prefix;
359
360 my $prefix_abs = abs_path($prefix);
361 my $srcdir_abs = abs_path($srcdir);
362
363 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
364 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
365
366 $ENV{PREFIX} = $prefix;
367 $ENV{PREFIX_ABS} = $prefix_abs;
368 $ENV{SRCDIR} = $srcdir;
369 $ENV{SRCDIR_ABS} = $srcdir_abs;
370
371 my $tls_enabled = not $opt_quick;
372 if (defined($ENV{RUN_FROM_BUILD_FARM}) and 
373         ($ENV{RUN_FROM_BUILD_FARM} eq "yes")) {
374         $opt_format = "buildfarm";
375 }
376
377 $ENV{TLS_ENABLED} = ($tls_enabled?"yes":"no");
378 $ENV{LD_LDB_MODULE_PATH} = "$old_pwd/bin/modules/ldb";
379 $ENV{LD_SAMBA_MODULE_PATH} = "$old_pwd/bin/modules";
380 if (defined($ENV{LD_LIBRARY_PATH})) {
381         $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared:$ENV{LD_LIBRARY_PATH}";
382 } else {
383         $ENV{LD_LIBRARY_PATH} = "$old_pwd/bin/shared";
384 }
385 if (defined($ENV{PKG_CONFIG_PATH})) {
386         $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig:$ENV{PKG_CONFIG_PATH}";
387 } else { 
388         $ENV{PKG_CONFIG_PATH} = "$old_pwd/bin/pkgconfig";
389 }
390 $ENV{PATH} = "$old_pwd/bin:$ENV{PATH}";
391
392
393 if ($opt_socket_wrapper_pcap) {
394         # Socket wrapper pcap implies socket wrapper
395         $opt_socket_wrapper = 1;
396 }
397
398 my $socket_wrapper_dir;
399 if ($opt_socket_wrapper) {
400         $socket_wrapper_dir = SocketWrapper::setup_dir("$prefix/w", $opt_socket_wrapper_pcap);
401         print "SOCKET_WRAPPER_DIR=$socket_wrapper_dir\n";
402 } else {
403         warn("Not using socket wrapper, but also not running as root. Will not be able to listen on proper ports") unless $< == 0;
404 }
405
406 my $target;
407
408 if ($opt_target eq "samba4") {
409         $target = new Samba4("$srcdir/bin", $ldap, "$srcdir/setup");
410 } elsif ($opt_target eq "samba3") {
411         if ($opt_socket_wrapper and `smbd -b | grep SOCKET_WRAPPER` eq "") {
412                 die("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'.  Exiting....");
413         }
414
415         $target = new Samba3($opt_bindir);
416 } elsif ($opt_target eq "win") {
417         die("Windows tests will not run with socket wrapper enabled.") 
418                 if ($opt_socket_wrapper);
419         $target = new Windows();
420 }
421
422 if (defined($opt_expected_failures)) {
423         open(KNOWN, "<$opt_expected_failures") or die("unable to read known failures file: $!");
424         while (<KNOWN>) { 
425                 chomp; 
426                 s/([ \t]+)\#(.*)$//;
427                 push (@expected_failures, $_); }
428         close(KNOWN);
429 }
430
431 if (defined($opt_skip)) {
432         open(SKIP, "<$opt_skip") or die("unable to read skip file: $!");
433         while (<SKIP>) { 
434                 chomp; 
435                 s/([ \t]+)\#(.*)$//;
436                 push (@skips, $_); }
437         close(SKIP);
438 }
439
440 my $interfaces = join(',', ("127.0.0.6/8", 
441                             "127.0.0.7/8",
442                             "127.0.0.8/8",
443                             "127.0.0.9/8",
444                             "127.0.0.10/8",
445                             "127.0.0.11/8"));
446
447 my $conffile = "$prefix_abs/client/client.conf";
448
449 sub write_clientconf($$)
450 {
451         my ($conffile, $vars) = @_;
452
453         mkdir("$prefix/client", 0777) unless -d "$prefix/client";
454         
455         if ( -d "$prefix/client/private" ) {
456                 unlink <$prefix/client/private/*>;
457         } else {
458                 mkdir("$prefix/client/private", 0777);
459         }
460
461         open(CF, ">$conffile");
462         print CF "[global]\n";
463         if (defined($ENV{VALGRIND})) {
464                 print CF "\ticonv:native = true\n";
465         } else {
466                 print CF "\ticonv:native = false\n";
467         }
468         print CF "\tnetbios name = client\n";
469         if (defined($vars->{DOMAIN})) {
470                 print CF "\tworkgroup = $vars->{DOMAIN}\n";
471         }
472         if (defined($vars->{REALM})) {
473                 print CF "\trealm = $vars->{REALM}\n";
474         }
475         if (defined($vars->{NCALRPCDIR})) {
476                 print CF "\tncalrpc dir = $vars->{NCALRPCDIR}\n";
477         }
478         if (defined($vars->{PIDDIR})) {
479                 print CF "\tpid directory = $vars->{PIDDIR}\n";
480         }
481         if (defined($vars->{WINBINDD_SOCKET_DIR})) {
482                 print CF "\twinbindd socket directory = $vars->{WINBINDD_SOCKET_DIR}\n";
483         }
484         print CF "
485         private dir = $prefix_abs/client/private
486         js include = $srcdir_abs/scripting/libjs
487         name resolve order = bcast
488         interfaces = $interfaces
489         panic action = $srcdir_abs/script/gdb_backtrace \%PID\% \%PROG\%
490         max xmit = 32K
491         notify:inotify = false
492         ldb:nosync = true
493         system:anonymous = true
494         torture:basedir = $prefix_abs/client
495 #We don't want to pass our self-tests if the PAC code is wrong
496         gensec:require_pac = true
497 ";
498         close(CF);
499 }
500
501
502 my @torture_options = ();
503 push (@torture_options, "--configfile=$conffile");
504 # ensure any one smbtorture call doesn't run too long
505 push (@torture_options, "--maximum-runtime=$torture_maxtime");
506 push (@torture_options, "--target=$opt_target");
507 push (@torture_options, "--basedir=$prefix");
508 push (@torture_options, "--option=torture:progress=no") if ($opt_format eq "buildfarm");
509 push (@torture_options, "--format=subunit");
510 push (@torture_options, "--option=torture:quick=yes") if ($opt_quick);
511
512 $ENV{TORTURE_OPTIONS} = join(' ', @torture_options);
513 print "OPTIONS $ENV{TORTURE_OPTIONS}\n";
514
515 my @todo = ();
516
517 my $testsdir = "$srcdir/selftest";
518 $ENV{SMB_CONF_PATH} = "$conffile";
519 $ENV{CONFIGURATION} = "--configfile=$conffile";
520
521 my %required_envs = ();
522
523 if ($opt_quick) {
524         open(IN, "$testsdir/tests_quick.sh|");
525 } else {
526         open(IN, "$testsdir/tests_all.sh|");
527 }
528 while (<IN>) {
529         if ($_ eq "-- TEST --\n") {
530                 my $name = <IN>;
531                 $name =~ s/\n//g;
532                 my $env = <IN>;
533                 $env =~ s/\n//g;
534                 my $cmdline = <IN>;
535                 $cmdline =~ s/\n//g;
536                 if (not defined($tests) or $name =~ /$tests/) {
537                         $required_envs{$env} = 1;
538                         push (@todo, [$name, $env, $cmdline]);
539                 }
540         } else {
541                 print;
542         }
543 }
544 close(IN) or die("Error creating recipe");
545
546 my $suitestotal = $#todo + 1;
547 my $i = 0;
548 $| = 1;
549
550 my %running_envs = ();
551
552 my @exported_envvars = (
553         # domain stuff
554         "DOMAIN",
555         "REALM",
556
557         # domain controller stuff
558         "DC_SERVER",
559         "DC_SERVER_IP",
560         "DC_NETBIOSNAME",
561         "DC_NETBIOSALIAS",
562
563         # server stuff
564         "SERVER",
565         "SERVER_IP",
566         "NETBIOSNAME",
567         "NETBIOSALIAS",
568
569         # user stuff
570         "USERNAME",
571         "PASSWORD",
572         "DC_USERNAME",
573         "DC_PASSWORD",
574
575         # misc stuff
576         "KRB5_CONFIG",
577         "WINBINDD_SOCKET_DIR"
578 );
579
580 sub setup_env($)
581 {
582         my ($envname) = @_;
583
584         my $testenv_vars;
585         if ($envname eq "none") {
586                 $testenv_vars = {};
587         } elsif (defined($running_envs{$envname})) {
588                 $testenv_vars = $running_envs{$envname};
589                 if (not $target->check_env($testenv_vars)) {
590                         $testenv_vars = undef;
591                 }
592         } else {
593                 $testenv_vars = $target->setup_env($envname, $prefix);
594         }
595
596         return undef unless defined($testenv_vars);
597
598         SocketWrapper::set_default_iface(6);
599         write_clientconf($conffile, $testenv_vars);
600
601         foreach (@exported_envvars) {
602                 if (defined($testenv_vars->{$_})) {
603                         $ENV{$_} = $testenv_vars->{$_};
604                 } else {
605                         delete $ENV{$_};
606                 }
607         }
608
609         $running_envs{$envname} = $testenv_vars;
610         return $testenv_vars;
611 }
612
613 sub exported_envvars_str($)
614 {
615         my ($testenv_vars) = @_;
616         my $out = "";
617
618         foreach (@exported_envvars) {
619                 next unless defined($testenv_vars->{$_});
620                 $out .= $_."=".$testenv_vars->{$_}."\n";
621         }
622
623         return $out;
624 }
625
626 sub getlog_env($)
627 {
628         my ($envname) = @_;
629         return "" if ($envname eq "none");
630         return $target->getlog_env($running_envs{$envname});
631 }
632
633 sub check_env($)
634 {
635         my ($envname) = @_;
636         return 1 if ($envname eq "none");
637         return $target->check_env($running_envs{$envname});
638 }
639
640 sub teardown_env($)
641 {
642         my ($envname) = @_;
643         return if ($envname eq "none");
644         $target->teardown_env($running_envs{$envname});
645         delete $running_envs{$envname};
646 }
647
648 my $msg_ops;
649 if ($opt_format eq "buildfarm") {
650         require output::buildfarm;
651         $msg_ops = new output::buildfarm();
652 } elsif ($opt_format eq "plain") {
653         require output::plain;
654         $msg_ops = new output::plain($opt_verbose, $opt_immediate, $statistics);
655 } elsif ($opt_format eq "html") {
656         require output::html;
657         mkdir("test-results", 0777);
658         $msg_ops = new output::html("test-results", $statistics);
659 } else {
660         die("Invalid output format '$opt_format'");
661 }
662
663 if ($opt_no_lazy_setup) {
664         setup_env($_) foreach (keys %required_envs);
665 }
666
667 if ($opt_testenv) {
668         my $testenv_name = $ENV{SELFTEST_TESTENV};
669         $testenv_name = "dc" unless defined($testenv_name);
670
671         my $testenv_vars = setup_env($testenv_name);
672
673         $ENV{PIDDIR} = $testenv_vars->{PIDDIR};
674
675         my $envvarstr = exported_envvars_str($testenv_vars);
676
677         my $term = ($ENV{TERM} or "xterm");
678         system("$term -e 'echo -e \"
679 Welcome to the Samba4 Test environment '$testenv_name'
680
681 This matches the client environment used in make test
682 smbd is pid `cat \$PIDDIR/smbd.pid`
683
684 Some useful environment variables:
685 TORTURE_OPTIONS=\$TORTURE_OPTIONS
686 CONFIGURATION=\$CONFIGURATION
687
688 $envvarstr
689 \" && bash'");
690         teardown_env($testenv_name);
691 } else {
692         foreach (@todo) {
693                 $i++;
694                 my $cmd = $$_[2];
695                 $cmd =~ s/([\(\)])/\\$1/g;
696                 my $name = $$_[0];
697                 my $envname = $$_[1];
698                 
699                 if (skip($name)) {
700                         $msg_ops->skip_testsuite($name);
701                         $statistics->{SUITES_SKIPPED}++;
702                         next;
703                 }
704
705                 my $envvars = setup_env($envname);
706                 if (not defined($envvars)) {
707                         $statistics->{SUITES_FAIL}++;
708                         $statistics->{TESTS_ERROR}++;
709                         $msg_ops->missing_env($name, $envname);
710                         next;
711                 }
712
713                 run_testsuite($envname, $name, $cmd, $i, $suitestotal, $msg_ops);
714
715                 if (defined($opt_analyse_cmd)) {
716                         system("$opt_analyse_cmd \"$name\"");
717                 }
718
719                 teardown_env($envname) if ($opt_resetup_env);
720         }
721 }
722
723 print "\n";
724
725 teardown_env($_) foreach (keys %running_envs);
726
727 $target->stop();
728
729 $statistics->{END_TIME} = time();
730 my $duration = ($statistics->{END_TIME}-$statistics->{START_TIME});
731 $msg_ops->summary();
732 print "DURATION: $duration seconds\n";
733
734 my $failed = 0;
735
736 # if there were any valgrind failures, show them
737 foreach (<$prefix/valgrind.log*>) {
738         next unless (-s $_);
739         system("grep DWARF2.CFI.reader $_ > /dev/null");
740         if ($? >> 8 == 0) {
741             print "VALGRIND FAILURE\n";
742             $failed++;
743             system("cat $_");
744         }
745 }
746
747 if ($opt_format eq "buildfarm") {
748         print "TEST STATUS: $statistics->{SUITES_FAIL}\n";
749 }
750
751 exit $statistics->{SUITES_FAIL};