Replace the hacky and broken pipeline in testdriver.sh with a custom-written
tool in C; much more robust and easier to understand, as well as avoiding the dependency on timeout (which isn't Posix).
This commit is contained in:
parent
4f446467c8
commit
960584c0f3
|
@ -45,10 +45,11 @@ definerule("plat_testsuite",
|
|||
outleaves = { "stamp" },
|
||||
ins = {
|
||||
bin,
|
||||
"tests/plat/testdriver.sh"
|
||||
"tests/plat/testdriver.sh",
|
||||
"util/build+testrunner"
|
||||
},
|
||||
commands = {
|
||||
"%{ins[2]} "..e.method.." %{ins[1]} 5",
|
||||
"%{ins[2]} "..e.method.." %{ins[1]} 5 %{ins[3]}",
|
||||
"touch %{outs}"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,50 +2,49 @@
|
|||
method=$1
|
||||
img=$2
|
||||
timeout=$3
|
||||
timeoutprog=$4
|
||||
|
||||
pipe=/tmp/$$.testdriver.pipe
|
||||
mknod $pipe p
|
||||
trap "rm -f $pipe" EXIT
|
||||
set -e
|
||||
|
||||
result=/tmp/$$.testdriver.result
|
||||
trap "rm -f $result" EXIT
|
||||
|
||||
pidfile=/tmp/$$.testdriver.pid
|
||||
trap "rm -f $pidfile" EXIT
|
||||
errcho() {
|
||||
>&2 echo "$*"
|
||||
}
|
||||
|
||||
case $method in
|
||||
qemu-system-*)
|
||||
if ! command -v $method >/dev/null 2>&1 ; then
|
||||
echo "Warning: $method not installed, skipping test"
|
||||
exit 0
|
||||
fi
|
||||
get_test_output() {
|
||||
case $method in
|
||||
qemu-system-*)
|
||||
if ! command -v $method >/dev/null 2>&1 ; then
|
||||
errcho "Warning: $method not installed, skipping test"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case $method in
|
||||
qemu-system-i386) img="-drive file=$img,if=floppy,format=raw" ;;
|
||||
qemu-system-ppc) img="-kernel $img" ;;
|
||||
esac
|
||||
case $method in
|
||||
qemu-system-i386) img="-drive file=$img,if=floppy,format=raw" ;;
|
||||
qemu-system-ppc) img="-kernel $img" ;;
|
||||
esac
|
||||
|
||||
( $method -nographic $img 2>&1 & echo $! > $pidfile ) \
|
||||
| tee $result \
|
||||
| ( timeout $timeout grep -l -q @@FINISHED ; echo ) \
|
||||
| ( read dummy && kill $(cat $pidfile) )
|
||||
$timeoutprog -t $timeout -- $method -nographic $img > $result
|
||||
;;
|
||||
|
||||
;;
|
||||
qemu-*)
|
||||
if ! command -v $method >/dev/null 2>&1 ; then
|
||||
errcho "Warning: $method not installed, skipping test"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
qemu-*)
|
||||
if ! command -v $method >/dev/null 2>&1 ; then
|
||||
echo "Warning: $method not installed, skipping test"
|
||||
exit 0
|
||||
fi
|
||||
$method $img > $result
|
||||
;;
|
||||
|
||||
$method $img > $result
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Error: $method not known by testdriver"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
*)
|
||||
errcho "Error: $method not known by testdriver"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_test_output > $result
|
||||
( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1
|
||||
exit 0
|
||||
|
|
7
util/build/build.lua
Normal file
7
util/build/build.lua
Normal file
|
@ -0,0 +1,7 @@
|
|||
cprogram {
|
||||
name = "testrunner",
|
||||
srcs = { "./testrunner.c" },
|
||||
deps = {
|
||||
"modules/src/data+lib"
|
||||
}
|
||||
}
|
104
util/build/testrunner.c
Normal file
104
util/build/testrunner.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <setjmp.h>
|
||||
#include "diagnostics.h"
|
||||
|
||||
static bool timed_out = false;
|
||||
static bool child_exited = false;
|
||||
static char** command = NULL;
|
||||
static int timeout = 0;
|
||||
static jmp_buf exit_jmp;
|
||||
|
||||
static void parse_arguments(int argc, char* const argv[])
|
||||
{
|
||||
program_name = argv[0];
|
||||
for (;;)
|
||||
{
|
||||
int c = getopt(argc, argv, "t:");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 't':
|
||||
timeout = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("syntax: testrunner <timeout in secs> -- <command>\n");
|
||||
}
|
||||
}
|
||||
|
||||
command = &argv[optind];
|
||||
if (!command[0])
|
||||
fatal("you must supply a command");
|
||||
if (timeout <= 0)
|
||||
fatal("timeout missing or invalid");
|
||||
}
|
||||
|
||||
static void sigalrm_cb(int sigraised)
|
||||
{
|
||||
timed_out = true;
|
||||
longjmp(exit_jmp, 1);
|
||||
}
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
const int READ = 0;
|
||||
const int WRITE = 1;
|
||||
|
||||
int fds[2];
|
||||
int pid;
|
||||
FILE* childin;
|
||||
int wstatus;
|
||||
char buffer[4096];
|
||||
|
||||
parse_arguments(argc, argv);
|
||||
|
||||
if (setjmp(exit_jmp) == 0)
|
||||
{
|
||||
/* First time through. */
|
||||
|
||||
signal(SIGALRM, sigalrm_cb);
|
||||
alarm(timeout);
|
||||
|
||||
pipe(fds);
|
||||
pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
/* Child */
|
||||
close(fds[READ]);
|
||||
close(0);
|
||||
dup2(fds[WRITE], 1);
|
||||
dup2(fds[WRITE], 2);
|
||||
execvp(command[0], command);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
childin = fdopen(fds[READ], "r");
|
||||
while (!timed_out)
|
||||
{
|
||||
if (!fgets(buffer, sizeof(buffer), childin))
|
||||
break;
|
||||
fputs(buffer, stdout);
|
||||
|
||||
if (strcmp(buffer, "@@FINISHED\n") == 0)
|
||||
break;
|
||||
if (strcmp(buffer, "@@FINISHED\r\n") == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reached via longjmp, EOF, or seeing a @@FINISHED. */
|
||||
|
||||
kill(pid, SIGKILL);
|
||||
waitpid(pid, &wstatus, 0);
|
||||
if (timed_out)
|
||||
exit(1);
|
||||
exit(WEXITSTATUS(wstatus));
|
||||
}
|
Loading…
Reference in a new issue