5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
24 # Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
38 $OPTSTR = 'abd:fghi:jlnqsx:';
39 $USAGE = "Usage: $PNAME [-abfghjlnqs] [-d dir] [-i isa] "
40 . "[-x opt[=arg]] [file | dir ...]\n";
41 ($MACH = `uname -p`) =~ s/\W*\n//;
42 ($PLATFORM = `uname -i`) =~ s/\W*\n//;
46 $ksh_path = '/usr/local/bin/ksh';
54 # If no test files are specified on the command-line, execute a find on "."
55 # and append any tst.*.d, tst.*.ksh, err.*.d or drp.*.d files found within
60 push(@files, $File::Find::name)
61 if ($_ =~ /^(tst|err|drp)\..+\.(d|ksh)$/ && -f "$_");
68 $s = substr($s, 0, $i) if (($i = rindex($s, '/')) != -1);
69 return $i == -1 ? '.' : $i == 0 ? '/' : $s;
75 print "\t -a execute test suite using anonymous enablings\n";
76 print "\t -b execute bad ioctl test program\n";
77 print "\t -d specify directory for test results files and cores\n";
78 print "\t -g enable libumem debugging when running tests\n";
79 print "\t -f force bypassed tests to run\n";
80 print "\t -h display verbose usage message\n";
81 print "\t -i specify ISA to test instead of isaexec(3C) default\n";
82 print "\t -j execute test suite using jdtrace (Java API) only\n";
83 print "\t -l save log file of results and PIDs used by tests\n";
84 print "\t -n execute test suite using dtrace(1m) only\n";
85 print "\t -q set quiet mode (only report errors and summary)\n";
86 print "\t -s save results files even for tests that pass\n";
87 print "\t -x pass corresponding -x argument to dtrace(1M)\n";
96 print LOG $msg if ($opt_l);
103 my($msg) = $parms[0];
104 my($errfile) = $parms[1];
106 my($dest) = basename($file);
108 while (-d "$opt_d/failure.$n") {
112 unless (mkdir "$opt_d/failure.$n") {
113 warn "ERROR: failed to make directory $opt_d/failure.$n: $!\n";
117 open(README, ">$opt_d/failure.$n/README");
118 print README "ERROR: " . $file . " " . $msg;
120 if (scalar @parms > 1) {
121 print README "; see $errfile\n";
123 if (-f "$opt_d/$pid.core") {
124 print README "; see $pid.core\n";
132 if (-f "$opt_d/$pid.out") {
133 rename("$opt_d/$pid.out", "$opt_d/failure.$n/$pid.out");
134 link("$file.out", "$opt_d/failure.$n/$dest.out");
137 if (-f "$opt_d/$pid.err") {
138 rename("$opt_d/$pid.err", "$opt_d/failure.$n/$pid.err");
139 link("$file.err", "$opt_d/failure.$n/$dest.err");
142 if (-f "$opt_d/$pid.core") {
143 rename("$opt_d/$pid.core", "$opt_d/failure.$n/$pid.core");
146 link("$file", "$opt_d/failure.$n/$dest");
148 $msg = "ERROR: " . $dest . " " . $msg;
150 if (scalar @parms > 1) {
151 $msg = $msg . "; see $errfile in failure.$n\n";
153 $msg = $msg . "; details in failure.$n\n";
163 print STDOUT $msg unless ($opt_q);
164 print LOG $msg if ($opt_l);
167 # Trim leading and trailing whitespace
176 # Load exception set of skipped tests from the file at the given
177 # pathname. The test names are assumed to be paths relative to $dt_tst,
178 # for example: common/aggs/tst.neglquant.d, and specify tests to be
180 sub load_exceptions {
185 if (length($listfile) > 0) {
186 exit(123) unless open(STDIN, "<$listfile");
190 # line is non-empty and not a comment
191 if ((length($line) > 0) && ($line =~ /^\s*[^\s#]/ )) {
192 $exceptions{trim($line)} = 1;
198 # Return 1 if the test is found in the exception set, 0 otherwise.
203 if (scalar(keys(%exceptions)) == 0) {
207 # hash absolute pathname after $dt_tst/
208 $file = abs_path($file);
209 $i = index($file, $dt_tst);
211 $file = substr($file, length($dt_tst) + 1);
212 return $exceptions{$file};
218 # Iterate over the set of test files specified on the command-line or by a find
219 # on "$defdir/common", "$defdir/$MACH" and "$defdir/$PLATFORM" and execute each
220 # one. If the test file is executable, we fork and exec it. If the test is a
221 # .ksh file, we run it with $ksh_path. Otherwise we run dtrace -s on it. If
222 # the file is named tst.* we assume it should return exit status 0. If the
223 # file is named err.* we assume it should return exit status 1. If the file is
224 # named err.D_[A-Z0-9]+[.*].d we use dtrace -xerrtags and examine stderr to
225 # ensure that a matching error tag was produced. If the file is named
226 # drp.[A-Z0-9]+[.*].d we use dtrace -xdroptags and examine stderr to ensure
227 # that a matching drop tag was produced. If any *.out or *.err files are found
228 # we perform output comparisons.
230 # run_tests takes two arguments: The first is the pathname of the dtrace
231 # command to invoke when running the tests. The second is the pathname
232 # of a file (may be the empty string) listing tests that ought to be
233 # skipped (skipped tests are listed as paths relative to $dt_tst, for
234 # example: common/aggs/tst.neglquant.d).
237 my($dtrace, $exceptions_path) = @_;
243 die "$PNAME: $dtrace not found\n" unless (-x "$dtrace");
244 logmsg($dtrace . "\n");
246 load_exceptions($exceptions_path);
248 foreach $file (sort @files) {
249 $file =~ m:.*/((.*)\.(\w+)):;
254 $dir = dirname($file);
259 if ($name =~ /^tst\./) {
260 $isksh = ($ext eq 'ksh');
262 } elsif ($name =~ /^err\.(D_[A-Z0-9_]+)\./) {
265 } elsif ($name =~ /^err\./) {
267 } elsif ($name =~ /^drp\.([A-Z0-9_]+)\./) {
271 errmsg("ERROR: $file is not a valid test file name\n");
275 $fullname = "$dir/$name";
276 $exe = "./$base.exe";
279 if ($opt_a && ($status != 0 || $tag != 0 || $droptag != 0 ||
280 -x $exe || $isksh || -x $fullname)) {
285 if (!$opt_f && is_exception("$dir/$name")) {
290 if (!$isksh && -x $exe) {
291 if (($exe_pid = fork()) == -1) {
293 "ERROR: failed to fork to run $exe: $!\n");
298 open(STDIN, '</dev/null');
302 warn "ERROR: failed to exec $exe: $!\n";
306 logmsg("testing $file ... ");
308 if (($pid = fork()) == -1) {
309 errmsg("ERROR: failed to fork to run test $file: $!\n");
314 open(STDIN, '</dev/null');
315 exit(125) unless open(STDOUT, ">$opt_d/$$.out");
316 exit(125) unless open(STDERR, ">$opt_d/$$.err");
318 unless (chdir($dir)) {
319 warn "ERROR: failed to chdir for $file: $!\n";
323 push(@dtrace_argv, '-xerrtags') if ($tag);
324 push(@dtrace_argv, '-xdroptags') if ($droptag);
325 push(@dtrace_argv, $exe_pid) if ($exe_pid != -1);
328 exit(123) unless open(STDIN, "<$name");
329 exec("$ksh_path /dev/stdin $dtrace");
331 warn "ERROR: $name is executable\n";
334 if ($tag == 0 && $status == $0 && $opt_a) {
335 push(@dtrace_argv, '-A');
338 push(@dtrace_argv, '-C');
339 push(@dtrace_argv, '-s');
340 push(@dtrace_argv, $name);
341 exec($dtrace, @dtrace_argv);
344 warn "ERROR: failed to exec for $file: $!\n";
348 if (waitpid($pid, 0) == -1) {
349 errmsg("ERROR: timed out waiting for $file\n");
350 kill(9, $exe_pid) if ($exe_pid != -1);
355 kill(9, $exe_pid) if ($exe_pid != -1);
357 if ($tag == 0 && $status == $0 && $opt_a) {
359 # We can chuck the earler output.
361 unlink($pid . '.out');
362 unlink($pid . '.err');
365 # This is an anonymous enabling. We need to get
366 # the module unloaded.
368 system("dtrace -ae 1> /dev/null 2> /dev/null");
369 system("svcadm disable -s " .
370 "svc:/network/nfs/mapid:default");
371 system("modunload -i 0 ; modunload -i 0 ; " .
373 if (!system("modinfo | grep dtrace")) {
374 warn "ERROR: couldn't unload dtrace\n";
375 system("svcadm enable " .
376 "-s svc:/network/nfs/mapid:default");
381 # DTrace is gone. Now update_drv(1M), and rip
382 # everything out again.
384 system("update_drv dtrace");
385 system("dtrace -ae 1> /dev/null 2> /dev/null");
386 system("modunload -i 0 ; modunload -i 0 ; " .
388 if (!system("modinfo | grep dtrace")) {
389 warn "ERROR: couldn't unload dtrace\n";
390 system("svcadm enable " .
391 "-s svc:/network/nfs/mapid:default");
396 # Now bring DTrace back in.
398 system("sync ; sync");
399 system("dtrace -l -n bogusprobe 1> /dev/null " .
401 system("svcadm enable -s " .
402 "svc:/network/nfs/mapid:default");
405 # That should have caused DTrace to reload with
406 # the new configuration file. Now we can try to
407 # snag our anonymous state.
409 if (($pid = fork()) == -1) {
410 errmsg("ERROR: failed to fork to run " .
416 open(STDIN, '</dev/null');
417 exit(125) unless open(STDOUT, ">$opt_d/$$.out");
418 exit(125) unless open(STDERR, ">$opt_d/$$.err");
420 push(@dtrace_argv, '-a');
422 unless (chdir($dir)) {
423 warn "ERROR: failed to chdir " .
428 exec($dtrace, @dtrace_argv);
429 warn "ERROR: failed to exec for $file: $!\n";
433 if (waitpid($pid, 0) == -1) {
434 errmsg("ERROR: timed out waiting for $file\n");
442 $wifexited = ($wstat & 0xFF) == 0;
443 $wexitstat = ($wstat >> 8) & 0xFF;
444 $wtermsig = ($wstat & 0x7F);
447 fail("died from signal $wtermsig");
451 if ($wexitstat == 125) {
452 die "$PNAME: failed to create output file in $opt_d " .
453 "(cd elsewhere or use -d)\n";
456 if ($wexitstat != $status) {
457 fail("returned $wexitstat instead of $status");
461 if (-f "$file.out" &&
462 system("cmp -s $file.out $opt_d/$pid.out") != 0) {
463 fail("stdout mismatch", "$pid.out");
467 if (-f "$file.err" &&
468 system("cmp -s $file.err $opt_d/$pid.err") != 0) {
469 fail("stderr mismatch: see $pid.err");
474 open(TSTERR, "<$opt_d/$pid.err");
478 unless ($tsterr =~ /: \[$tag\] line \d+:/) {
479 fail("errtag mismatch: see $pid.err");
486 open(TSTERR, "<$opt_d/$pid.err");
489 if (/\[$droptag\] /) {
498 fail("droptag mismatch: see $pid.err");
504 unlink($pid . '.out');
505 unlink($pid . '.err');
511 # If we're running with anonymous enablings, we need to
512 # restore the .conf file.
514 system("dtrace -A 1> /dev/null 2> /dev/null");
515 system("dtrace -ae 1> /dev/null 2> /dev/null");
516 system("modunload -i 0 ; modunload -i 0 ; modunload -i 0");
517 system("update_drv dtrace");
520 $total = scalar(@files);
521 $failed = $errs - $failed;
522 $passed = ($total - $failed - $bypassed);
523 $results{$dtrace} = {
525 "bypassed" => $bypassed,
531 die $USAGE unless (getopts($OPTSTR));
534 foreach $arg (@ARGV) {
538 find(\&wanted, $arg);
540 die "$PNAME: $arg is not a valid file or directory\n";
544 $dt_tst = '/opt/SUNWdtrt/tst';
545 $dt_bin = '/opt/SUNWdtrt/bin';
546 $defdir = -d $dt_tst ? $dt_tst : '.';
547 $bindir = -d $dt_bin ? $dt_bin : '.';
549 find(\&wanted, "$defdir/common") if (scalar(@ARGV) == 0);
550 find(\&wanted, "$defdir/$MACH") if (scalar(@ARGV) == 0);
551 find(\&wanted, "$defdir/$PLATFORM") if (scalar(@ARGV) == 0);
552 die $USAGE if (scalar(@files) == 0);
554 $dtrace_path = '/usr/sbin/dtrace';
555 $jdtrace_path = "$bindir/jdtrace";
557 %exception_lists = ("$jdtrace_path" => "$bindir/exception.lst");
559 if ($opt_j || $opt_n || $opt_i) {
561 push(@dtrace_cmds, $dtrace_path) if ($opt_n);
562 push(@dtrace_cmds, $jdtrace_path) if ($opt_j);
563 push(@dtrace_cmds, "/usr/sbin/$opt_i/dtrace") if ($opt_i);
565 @dtrace_cmds = ($dtrace_path, $jdtrace_path);
569 die "$PNAME: -d arg must be absolute path\n" unless ($opt_d =~ /^\//);
570 die "$PNAME: -d arg $opt_d is not a directory\n" unless (-d "$opt_d");
571 system("coreadm -p $opt_d/%p.core");
574 system("coreadm -p $dir/%p.core");
579 push(@dtrace_argv, '-x');
580 push(@dtrace_argv, $opt_x);
583 die "$PNAME: failed to open $PNAME.$$.log: $!\n"
584 unless (!$opt_l || open(LOG, ">$PNAME.$$.log"));
586 $ENV{'DTRACE_DEBUG_REGSET'} = 'true';
589 $ENV{'UMEM_DEBUG'} = 'default,verbose';
590 $ENV{'UMEM_LOGGING'} = 'fail,contents';
591 $ENV{'LD_PRELOAD'} = 'libumem.so';
595 # Ensure that $PATH contains a cc(1) so that we can execute the
596 # test programs that require compilation of C code.
598 #$ENV{'PATH'} = $ENV{'PATH'} . ':/ws/onnv-tools/SUNWspro/SS11/bin';
601 logmsg("badioctl'ing ... ");
603 if (($badioctl = fork()) == -1) {
604 errmsg("ERROR: failed to fork to run badioctl: $!\n");
608 if ($badioctl == 0) {
609 open(STDIN, '</dev/null');
610 exit(125) unless open(STDOUT, ">$opt_d/$$.out");
611 exit(125) unless open(STDERR, ">$opt_d/$$.err");
613 exec($bindir . "/badioctl");
614 warn "ERROR: failed to exec badioctl: $!\n";
619 logmsg("[$badioctl]\n");
622 # If we're going to be bad, we're just going to iterate over each
625 foreach $file (sort @files) {
626 ($name = $file) =~ s:.*/::;
627 $dir = dirname($file);
629 if (!($name =~ /^tst\./ && $name =~ /\.d$/)) {
633 logmsg("baddof'ing $file ... ");
635 if (($pid = fork()) == -1) {
636 errmsg("ERROR: failed to fork to run baddof: $!\n");
641 open(STDIN, '</dev/null');
642 exit(125) unless open(STDOUT, ">$opt_d/$$.out");
643 exit(125) unless open(STDERR, ">$opt_d/$$.err");
645 unless (chdir($dir)) {
646 warn "ERROR: failed to chdir for $file: $!\n";
650 exec($bindir . "/baddof", $name);
652 warn "ERROR: failed to exec for $file: $!\n";
663 unlink($pid . '.out');
664 unlink($pid . '.err');
669 waitpid($badioctl, 0);
672 unlink($badioctl . '.out');
673 unlink($badioctl . '.err');
680 # Run all the tests specified on the command-line (the entire test suite
681 # by default) once for each dtrace command tested, skipping any tests
682 # not valid for that command.
684 foreach $dtrace_cmd (@dtrace_cmds) {
685 run_tests($dtrace_cmd, $exception_lists{$dtrace_cmd});
688 $opt_q = 0; # force final summary to appear regardless of -q option
690 logmsg("\n==== TEST RESULTS ====\n");
691 foreach $key (keys %results) {
692 my $passed = $results{$key}{"passed"};
693 my $bypassed = $results{$key}{"bypassed"};
694 my $failed = $results{$key}{"failed"};
695 my $total = $results{$key}{"total"};
697 logmsg("\n mode: " . $key . "\n");
698 logmsg(" passed: " . $passed . "\n");
700 logmsg(" bypassed: " . $bypassed . "\n");
702 logmsg(" failed: " . $failed . "\n");
703 logmsg(" total: " . $total . "\n");