4 # Script to supervise the execution of wvtest-based tests. It is a
5 # modified version of wvtestrun with some features added and without
6 # pretty-printing which was moved to wvformat script.
8 # It takes care of killing test (qemu or serial reader) when the test
9 # finishes or hangs. It has flexible timeout management and is able to
10 # check that the number of executed assertions is the same as was
13 # Copyright (C) 2011, 2012, Michal Sojka <sojka@os.inf.tu-dresden.de>
14 # Economic rights: Technische Universitaet Dresden (Germany)
16 # This file is part of NUL (NOVA user land).
18 # NUL is free software: you can redistribute it and/or
19 # modify it under the terms of the GNU General Public License version
20 # 2 as published by the Free Software Foundation.
22 # NUL is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 # General Public License version 2 for more details.
34 my $istty = -t STDOUT && $ENV{'TERM'} ne "dumb";
35 my $pty = new IO::Pty;
38 die "Cannot fork" if not defined $pid;
41 $pty->make_slave_controlling_terminal();
42 # setpgrp(); # Terminal won't send signals to the child
43 my $slave = $pty->slave();
45 $slave->clone_winsize_from(\*STDIN) if $istty;
48 open(STDIN,"<&". $slave->fileno())
49 or die "Couldn't reopen STDIN for reading, $!\n";
50 open(STDOUT,">&". $slave->fileno())
51 or die "Couldn't reopen STDOUT for writing, $!\n";
52 open(STDERR,">&". $slave->fileno())
53 or die "Couldn't reopen STDERR for writing, $!\n";
58 die "Cannot exec(@ARGV): $!";
62 #$pty->set_raw(); # from IO::Pty "try" script. Do we need this?
65 $pty->slave->clone_winsize_from(\*STDIN);
66 kill WINCH => $pid if $pid;
67 $SIG{WINCH} = \&winch;
70 $SIG{WINCH} = \&winch if $istty;
75 ($pid > 0) || die("pid is '$pid'?!\n");
77 local $SIG{CHLD} = sub { }; # this will wake us from sleep() faster
78 $count = kill -15, $pid;
81 kill -9, $pid if ($pid > 1);
89 local $SIG{INT} = sub { bigkill($pid); };
90 local $SIG{TERM} = sub { bigkill($pid); };
91 local $SIG{ALRM} = sub {
92 print STDERR "! $0: Alarm timed out! No test output for $timeout seconds. FAILED\n";
96 my $allstart = time();
98 my $tests_executed = 0;
100 my $waits_for_child = 0;
102 my $ignore_exit_patterns = 0;
103 my $expected_test_count = 0;
104 my $expected_test_base = 0;
106 sub matches_exit_pattern($)
108 return 0 if $ignore_exit_patterns;
109 if ($ENV{WVTEST_EXIT_PATTERN}) {
110 return /$ENV{WVTEST_EXIT_PATTERN}/
113 (/sc: done.$/ && $waits_for_child) ||
114 /resetting machine via method/ ||
115 /wvtest: done\s*$/ ||
116 / # .*System halted. *$/
121 sub check_number_of_tests()
123 if ($expected_test_count) {
124 my $executed = $tests_executed - $expected_test_base;
126 if ($executed == $expected_test_count) {
131 print "Expected $expected_test_count tests, executed $executed tests.\n"
133 print "! $0: tests_expected == tests_executed $result\n";
138 if ($ENV{WVTEST_OUTPUT}) {
139 open $wvtest_output, ">", $ENV{WVTEST_OUTPUT};
147 print $wvtest_output $_ if $wvtest_output;
151 if (/^(\([0-9]+\) (# )?)?!\s*(.*?)\s+(\S+)\s*$/) {
153 $tests_failed++ if ($4 ne "ok");
155 elsif (/wvtest: timeout (\d+)\s*$/) {
159 elsif (/sc: wait for child/) { $waits_for_child = 1; }
160 elsif (/wvtest: ignore exit patterns/) { $ignore_exit_patterns = 1; }
161 elsif (/wvtest: expect ([0-9]+) tests/) {
162 check_number_of_tests();
163 $expected_test_count = $1;
164 $expected_test_base = $tests_executed;
166 elsif (matches_exit_pattern($_))
168 if (!$ENV{WVTEST_NOKILL}) {
169 kill 15, $pid; # Kill novaboot or qemu
175 print "Keeping PID $pid alive\n";
176 print $wvtest_output "Keeping PID $pid alive\n" if $wvtest_output;
177 close($wvtest_output) if $wvtest_output;
180 # Continue printing on background
181 close($wvtest_output) if $wvtest_output;
182 while (<$pty>) { print; }
188 my $newpid = waitpid($pid, 0);
189 if ($newpid != $pid) {
190 die("waitpid returned '$newpid', expected '$pid'\n");
194 my $ret = ($code >> 8);
196 if ($code && !$ret) {
197 if ($kill_ok && $code == 15) {
198 # We have killed the child - it is OK
201 # return death-from-signal exits as >128. This is what bash does if you ran
202 # the program directly.
208 print "! $0: Program '", join(" ", @ARGV), "' returned non-zero exit code ($ret) FAILED\n";
211 if (!$ENV{WVTEST_EXIT_PATTERN}) {
212 printf "! $0: \$tests_executed > 0 %s\n", ($tests_executed > 0) ? "ok" : "FAILED";
214 check_number_of_tests();
216 if ($tests_failed > 0) { $ret = 1; }
217 if ($ret == 0 && $tests_executed == 0) { $ret = 1; }