From 8c482cb2f7019c2491f3bf4f25c4fb5d395ad5da Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Tue, 27 Oct 2026 00:28:35 +0100 Subject: add more checkers to the sanitizer and integration check runs --- tests/runner.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) (limited to 'tests/runner.c') diff --git a/tests/runner.c b/tests/runner.c index a92315e..71a5e2a 100644 --- a/tests/runner.c +++ b/tests/runner.c @@ -4,7 +4,11 @@ $id$ */ /* System */ +#include +#include #include +#include +#include /* Opentracker */ #include "test.h" @@ -31,15 +35,79 @@ static const struct module modules[] = {{"ot_urlencoded", test_urlencoded}, {"ot_accesslist", test_accesslist}, {NULL, NULL}}; -/* Run every module, or only those whose name contains argv[1] */ +struct tally { + unsigned long checks; + unsigned long failures; +}; + +/* Each module runs in a child of its own, so that a crash or a sanitizer + abort costs that module's results rather than every module after it. The + child reports its tally through a pipe; one that dies without reporting is + counted as a failure under its own name. */ +static void run_forked(const struct module *m) { + struct tally tally = {0, 0}; + int pipefd[2], status = 0; + pid_t child; + ssize_t got; + + if (pipe(pipefd)) { + test_failf(__FILE__, __LINE__, "pipe failed, cannot isolate %s", m->name); + return; + } + + fflush(stdout); /* or the child inherits a copy and prints it again */ + child = fork(); + if (child < 0) { + close(pipefd[0]); + close(pipefd[1]); + test_failf(__FILE__, __LINE__, "fork failed, cannot isolate %s", m->name); + return; + } + + if (!child) { + close(pipefd[0]); + test_checks = test_failures = 0; + m->run(); + tally.checks = test_checks; + tally.failures = test_failures; + if (write(pipefd[1], &tally, sizeof(tally)) != (ssize_t)sizeof(tally)) + _exit(1); + fflush(stdout); + _exit(0); + } + + close(pipefd[1]); + got = read(pipefd[0], &tally, sizeof(tally)); + close(pipefd[0]); + while (waitpid(child, &status, 0) < 0) + ; + + if (got == (ssize_t)sizeof(tally)) { + test_checks += tally.checks; + test_failures += tally.failures; + } + if (got != (ssize_t)sizeof(tally) || !WIFEXITED(status) || WEXITSTATUS(status)) + test_failf(__FILE__, __LINE__, "%s did not run to the end", m->name); +} + +/* Run every module, or only those whose name contains argv[1]. + OT_TEST_FORK=0 keeps everything in one process, which is what a debugger + wants. */ int main(int argc, char **argv) { + const char *fork_setting = getenv("OT_TEST_FORK"); + int isolate = !fork_setting || strcmp(fork_setting, "0"); const struct module *m; for (m = modules; m->name; ++m) { if (argc > 1 && !strstr(m->name, argv[1])) continue; test_module(m->name); - m->run(); + if (!isolate) { + m->run(); + continue; + } + test_case("the module runs to the end"); + run_forked(m); } return test_summary(); -- cgit v1.3