Exitcode handling in igt testcases has too ugly facets in combination with subtests: - When individual subtest needed to be skipped for different reasons we need to painstakingly thread this information through the test to make sure that we still succeed if just one testcase worked (for running it with the simple automake test runner in igt). But it also needs to correctly report the skip exit value if only this one skipped testcase has been run (e.g. when run with piglit or in QA's test infrastructure). - We'd prefer to easily skip (and also fail) subtests without hampering other subtests. Again threading the return value of each subtest through the code is cumbersome. To simplify test case writing use longjmps to be able to get out of subcases easily. But since longjmps are funny things thug it all away into the newly added drmtest_subtest_block macro. Note that if drmtest_skip is called outside of a subtest, but in a testcase with subtests all subsequent subtests will be automatically skipped. Signed-off-by: Daniel Vetter <daniel.vetter@xxxxxxxx> --- lib/drmtest.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- lib/drmtest.h | 10 +++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/lib/drmtest.c b/lib/drmtest.c index cae07a2..767c8dc 100644 --- a/lib/drmtest.c +++ b/lib/drmtest.c @@ -657,6 +657,9 @@ void drmtest_stop_signal_helper(void) /* subtests helpers */ static bool list_subtests = false; static char *run_single_subtest = NULL; +static bool in_subtest = false; +static bool test_with_subtests = false; +static bool skip_subtests_henceforth = false; void drmtest_subtest_init(int argc, char **argv) { @@ -667,6 +670,8 @@ void drmtest_subtest_init(int argc, char **argv) {NULL, 0, 0, 0,} }; + test_with_subtests = true; + /* supress getopt errors about unknown options */ opterr = 0; /* restrict the option parsing to long option names to avoid collisions @@ -695,16 +700,21 @@ out: */ bool drmtest_run_subtest(const char *subtest_name) { + assert(in_subtest == false); + if (list_subtests) { printf("%s\n", subtest_name); return false; } + if (skip_subtests_henceforth) + return false; + if (!run_single_subtest) { - return true; + return in_subtest = true; } else { if (strcmp(subtest_name, run_single_subtest) == 0) - return true; + return in_subtest = true; return false; } @@ -715,6 +725,69 @@ bool drmtest_only_list_subtests(void) return list_subtests; } +static bool skipped_one = false; +static bool succeeded_one = false; +static bool failed_one = false; +static int drmtest_exitcode; + +static void exit_subtest(void) __attribute__((noreturn)); +static void exit_subtest(void) +{ + in_subtest = false; + longjmp(drmtest_subtest_jmpbuf, 1); +} + +void drmtest_skip(void) +{ + skipped_one = true; + if (in_subtest) + exit_subtest(); + else if (test_with_subtests) + skip_subtests_henceforth = true; + else + exit(77); +} + +void drmtest_success(void) +{ + succeeded_one = true; + if (in_subtest) + exit_subtest(); +} + +void drmtest_fail(int exitcode) +{ + assert(exitcode != 0 && exitcode != 77); + + if (!failed_one) + drmtest_exitcode = exitcode; + + failed_one = true; + + if (in_subtest) + exit_subtest(); + else { + assert(!test_with_subtests); + exit(exitcode); + } +} + +int drmtest_retval(void) +{ + if (drmtest_only_list_subtests()) + return 0; + + /* Calling this without calling one of the above is a failure */ + assert(skipped_one || succeeded_one || failed_one); + + if (failed_one) + return drmtest_exitcode; + else if (succeeded_one) + return 0; + else + return 77; +} + static bool env_set(const char *env_var, bool default_value) { char *val; diff --git a/lib/drmtest.h b/lib/drmtest.h index ada8e81..13e25bb 100644 --- a/lib/drmtest.h +++ b/lib/drmtest.h @@ -32,6 +32,7 @@ #include <errno.h> #include <stdbool.h> #include <cairo.h> +#include <setjmp.h> #include "xf86drm.h" #include "xf86drmMode.h" @@ -93,10 +94,17 @@ void drmtest_permute_array(void *array, unsigned size, void drmtest_progress(const char *header, uint64_t i, uint64_t total); /* subtest infrastructure */ +jmp_buf drmtest_subtest_jmpbuf; void drmtest_subtest_init(int argc, char **argv); bool drmtest_run_subtest(const char *subtest_name); -#define drmtest_subtest_block(name) if (drmtest_run_subtest((name))) +#define drmtest_subtest_block(name) for (; drmtest_run_subtest((name)) && \ + (setjmp(drmtest_subtest_jmpbuf) == 0); \ + drmtest_success()) bool drmtest_only_list_subtests(void); +void drmtest_skip(void); +void drmtest_success(void); +void drmtest_fail(int exitcode) __attribute__((noreturn)); +int drmtest_retval(void); /* helpers to automatically reduce test runtime in simulation */ bool drmtest_run_in_simulation(void); -- 1.8.3.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx