test: add ability to collect test results from a nonforking test
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 16 Oct 2024 22:29:22 +0000 (08:29 +1000)
committerMarge Bot <emma+marge@anholt.net>
Wed, 30 Oct 2024 23:20:42 +0000 (23:20 +0000)
Use longjmp to try to get out of a test error. This will only work for
errors triggered by our own test suite (i.e. not for SIGSEGV and
friends) but that's good enough for most things.

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1067>

test/litest-runner.c
test/litest-runner.h
test/litest.c

index f9f996b91e1e650baa3389531599b9b541cc1ba7..c5507a352f32a9f30ed7222aed5054cefd9fbfca 100644 (file)
@@ -34,6 +34,7 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <setjmp.h>
 #include <valgrind/valgrind.h>
 
 #include "litest-runner.h"
@@ -42,6 +43,9 @@
 #include "util-list.h"
 #include "util-stringbuf.h"
 
+static bool use_jmpbuf; /* only used for max_forks = 0 */
+static jmp_buf jmpbuf;
+
 /* musl doesn't have this one but it's not that important */
 #ifndef HAVE_SIGABBREV_NP
 #define sigabbrev_np(...) "???"
@@ -587,10 +591,20 @@ litest_runner_test_update_errno(struct litest_runner_test *t, int error)
        }
 }
 
+__attribute__((noreturn))
+void
+litest_runner_abort(void)  {
+       if (use_jmpbuf) {
+               longjmp(jmpbuf, SIGABRT);
+       } else {
+               abort();
+       }
+}
+
 static int
 litest_runner_run_test(struct litest_runner *runner, struct litest_runner_test *t)
 {
-       int r = 0;
+       int r;
 
        t->result = LITEST_SYSTEM_ERROR;
 
@@ -599,7 +613,12 @@ litest_runner_run_test(struct litest_runner *runner, struct litest_runner_test *
        t->times.start_millis = us2ms(now);
 
        if (runner->max_forks == 0) {
-               t->result = litest_runner_test_run(&t->desc);
+               if (use_jmpbuf && setjmp(jmpbuf) == 0) {
+                       t->result = litest_runner_test_run(&t->desc);
+               } else {
+                       t->result = LITEST_FAIL;
+               }
+               r = 0; /* -Wclobbered */
        } else {
                r = litest_runner_fork_test(runner, t);
                if (r >= 0)
@@ -845,6 +864,8 @@ litest_runner_run_tests(struct litest_runner *runner)
        if (runner->global.setup)
                runner->global.setup(runner->global.userdata);
 
+       use_jmpbuf = runner->max_forks == 0;
+
        setup_sighandler(SIGINT);
 
        uint64_t now = 0;
index c557e1857e80d195cb66e207e17e42d21bdde9ca..14f0a11d6498bdb5249005d8a6d152f5b7d0e146 100644 (file)
@@ -92,3 +92,11 @@ litest_runner_set_setup_funcs(struct litest_runner *runner,
                              void *userdata);
 
 void litest_runner_destroy(struct litest_runner *runner);
+
+/*
+ * Function to call abort(). Depending on the number of forks permitted,
+ * this function may simply abort() or it may longjmp back out to collect
+ * errors from non-forking tests.
+ */
+__attribute__((noreturn))
+void litest_runner_abort(void);
index 858598e88b29f22fc04bec72f3e9d30921e49e0d..47a6a7e7c99d793eda6c097bde2de24bcc8c29c9 100644 (file)
@@ -185,7 +185,7 @@ litest_fail_condition(const char *file,
 
        litest_log("in %s() (%s:%d)\n", func, file, line);
        litest_backtrace();
-       abort();
+       litest_runner_abort();
 }
 
 __attribute__((noreturn))
@@ -203,7 +203,7 @@ litest_fail_comparison_int(const char *file,
        litest_log("Resolved to: %d %s %d\n", a, operator, b);
        litest_log("in %s() (%s:%d)\n", func, file, line);
        litest_backtrace();
-       abort();
+       litest_runner_abort();
 }
 
 __attribute__((noreturn))
@@ -221,7 +221,7 @@ litest_fail_comparison_double(const char *file,
        litest_log("Resolved to: %.3f %s %.3f\n", a, operator, b);
        litest_log("in %s() (%s:%d)\n", func, file, line);
        litest_backtrace();
-       abort();
+       litest_runner_abort();
 }
 
 __attribute__((noreturn))
@@ -234,7 +234,7 @@ litest_fail_comparison_ptr(const char *file,
        litest_log("FAILED COMPARISON: %s\n", comparison);
        litest_log("in %s() (%s:%d)\n", func, file, line);
        litest_backtrace();
-       abort();
+       litest_runner_abort();
 }
 
 __attribute__((noreturn))
@@ -251,7 +251,7 @@ litest_fail_comparison_str(const char *file,
        litest_log("Resolved to: %s %s %s\n", astr, operator, bstr);
        litest_log("in %s() (%s:%d)\n", func, file, line);
        litest_backtrace();
-       abort();
+       litest_runner_abort();
 }
 
 struct test {
@@ -3257,7 +3257,7 @@ _litest_assert_event_type_is_one_of(struct libinput_event *event, ...)
        fprintf(stderr, "\nWrong event is: ");
        litest_print_event(event);
        litest_backtrace();
-       abort();
+       litest_runner_abort();
 }
 
 void
@@ -3298,7 +3298,7 @@ _litest_assert_event_type_not_one_of(struct libinput_event *event, ...)
        fprintf(stderr, "\nWrong event is: ");
        litest_print_event(event);
        litest_backtrace();
-       abort();
+       litest_runner_abort();
 }
 
 void