/* This software was written by Dirk Engling It is considered beerware. Prost. Skol. Cheers or whatever. $id$ */ /* System */ #include #include #include #include #include /* Opentracker */ #include "test.h" struct module { const char *name; void (*run)(void); }; static const struct module modules[] = {{"ot_urlencoded", test_urlencoded}, {"ot_iovec", test_iovec}, {"ot_vector", test_vector}, {"ot_random", test_random}, {"ot_hex", test_hex}, {"ot_scan", test_scan}, {"ot_buf", test_buf}, {"ot_ip", test_ip}, {"ot_socket", test_socket}, {"ot_mutex", test_mutex}, {"ot_batch", test_batch}, {"ot_fdstate", test_fdstate}, {"ot_event", test_event}, {"ot_fmt", test_fmt}, {"ot_accesslist", test_accesslist}, {NULL, NULL}}; 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); if (!isolate) { m->run(); continue; } test_case("the module runs to the end"); run_forked(m); } return test_summary(); }