Merge from default.

This commit is contained in:
David Given 2016-12-02 00:25:50 +01:00
commit 07e654d6e3
9 changed files with 222 additions and 49 deletions

View file

@ -63,7 +63,7 @@ PLATDEP = $(INSDIR)/lib/ack
.NOTPARALLEL:
MAKECMDGOALS ?= +ack
MAKECMDGOALS ?= +ack +tests
BUILD_FILES = $(shell find * -name '*.lua')
ifneq ($(shell which ninja),)

View file

@ -47,8 +47,18 @@ installable {
"examples+pkg",
plat_packages
},
deps = {
test_packages
}
}
normalrule {
name = "tests",
ins = {
"first/testsummary.sh",
test_packages
},
outleaves = {
"stamp"
},
commands = {
"%{ins}"
}
}

37
first/testsummary.sh Executable file
View file

@ -0,0 +1,37 @@
#!/bin/sh
echo ""
succeeding="$(find "$@" -size 0)"
notsucceeding="$(find "$@" ! -size 0)"
skipped="$(grep -l @@SKIPPED $notsucceeding)"
timedout="$(grep -l @@TIMEDOUT $notsucceeding)"
failed="$(grep -l @@FAIL $notsucceeding)"
for a in $failed $timedout; do
echo "**** $a"
cat $a
echo ""
done
echo "$(echo $succeeding | wc -w) tests passed"
echo "$(echo $notsucceeding | wc -w) tests failed to pass"
echo "$(echo $skipped | wc -w) were skipped (see build log for details)"
echo "$(echo $timedout | wc -w) timed out"
echo "$(echo $failed | wc -w) failed"
echo ""
if [ "$failed" != "" -o "$timedout" != "" ]; then
echo "Test status: SAD FACE (tests are failing)"
exit 1
fi
if [ "$succeeding" = "" ]; then
echo "Test status: PUZZLED FACE (all tests were skipped)"
exit 0
fi
if [ "$skipped" != "" ]; then
echo "Test status: MILDLY PLEASED FACE (some tests were skipped, but the rest pass)"
exit 0
fi
echo "Test status: HAPPY FACE (all tests are passing)"
exit 0

View file

@ -6,4 +6,3 @@ void _m_a_i_n(void)
ASSERT(0 == 0);
finished();
}

View file

@ -42,23 +42,21 @@ definerule("plat_testsuite",
tests[#tests+1] = normalrule {
name = fs,
outleaves = { "stamp" },
outleaves = { e.plat.."-"..fs.."-testlog.txt" },
ins = {
bin,
"tests/plat/testdriver.sh"
"tests/plat/testdriver.sh",
"util/build+testrunner"
},
commands = {
"%{ins[2]} "..e.method.." %{ins[1]} 5",
"touch %{outs}"
"(%{ins[2]} "..e.method.." %{ins[1]} 5 %{ins[3]} || echo FAILED) 2>&1 > %{outs}",
}
}
end
return normalrule {
return bundle {
name = e.name,
outleaves = { "stamp" },
ins = tests,
commands = { "touch %{outs}" }
srcs = tests,
}
end
)

View file

@ -26,7 +26,10 @@ void writehex(uint32_t code)
void fail(uint32_t code)
{
write(1, "@@FAIL 0x", 10);
static const char fail_msg[] = "@@FAIL 0x";
static const char nl_msg[] = "\n";
write(1, fail_msg, sizeof(fail_msg)-1);
writehex(code);
write(1, "\n", 1);
write(1, nl_msg, sizeof(nl_msg)-1);
}

View file

@ -2,21 +2,23 @@
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 "$*"
}
get_test_output() {
case $method in
qemu-system-*)
if ! command -v $method >/dev/null 2>&1 ; then
echo "Warning: $method not installed, skipping test"
errcho "Warning: $method not installed, skipping test"
echo "@@SKIPPED"
exit 0
fi
@ -25,27 +27,26 @@ case $method in
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 2>&1 > $result
;;
qemu-*)
if ! command -v $method >/dev/null 2>&1 ; then
echo "Warning: $method not installed, skipping test"
errcho "Warning: $method not installed, skipping test"
echo "@@SKIPPED"
exit 0
fi
$method $img > $result
$method $img 2>&1 > $result
;;
*)
echo "Error: $method not known by testdriver"
errcho "Error: $method not known by testdriver"
exit 1
;;
esac
}
( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1
get_test_output
( grep -q '@@FAIL\|@@SKIPPED' $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1
exit 0

8
util/build/build.lua Normal file
View file

@ -0,0 +1,8 @@
cprogram {
name = "testrunner",
srcs = { "./testrunner.c" },
deps = {
"modules/src/data+lib"
}
}

117
util/build/testrunner.c Normal file
View file

@ -0,0 +1,117 @@
#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 <ctype.h>
#include "diagnostics.h"
static bool timed_out = false;
static bool child_exited = false;
static char* const* command = NULL;
static int timeout = 0;
static int pid = 0;
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;
if (pid)
kill(pid, SIGKILL);
}
int main(int argc, char* const argv[])
{
const int READ = 0;
const int WRITE = 1;
int fds[2];
FILE* childin;
int wstatus;
char buffer[4096];
char* p;
parse_arguments(argc, argv);
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);
}
else
{
/* Parent */
close(fds[WRITE]);
signal(SIGALRM, sigalrm_cb);
alarm(timeout);
}
childin = fdopen(fds[READ], "r");
if (!childin)
fatal("cannot open pipe");
while (!timed_out)
{
if (!fgets(buffer, sizeof(buffer), childin))
break;
fputs(buffer, stdout);
p = buffer;
while (isspace(*p))
p++;
if (strcmp(p, "@@FINISHED\n") == 0)
break;
if (strcmp(p, "@@FINISHED\r\n") == 0)
break;
}
/* Reached via EOF or seeing a @@FINISHED. */
alarm(0);
kill(pid, SIGKILL);
waitpid(pid, &wstatus, 0);
if (timed_out)
{
fprintf(stderr, "@@TIMEDOUT\n");
exit(1);
}
exit(WEXITSTATUS(wstatus));
}