From: Rusty Russell Date: Mon, 29 Aug 2011 23:57:39 +0000 (+0930) Subject: ccanlint: run tests under valgrind initially. X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=ad6a6711a1b703793e49206e10d6dcf1722eb424;hp=b1524d16e5e98dafee5a192511a557ace0b5afb3 ccanlint: run tests under valgrind initially. Unless it's not available or suppressed, we might as well run it under valgrind the first time, which speeds things a little. We save the valgrind output file for tests_pass_valgrind's use later. --- diff --git a/tools/ccanlint/ccanlint.h b/tools/ccanlint/ccanlint.h index 9a83e053..9f15ef39 100644 --- a/tools/ccanlint/ccanlint.h +++ b/tools/ccanlint/ccanlint.h @@ -179,6 +179,9 @@ struct ccan_file { /* Compiled with coverage information. */ char *cov_compiled; + /* Filename containing output from valgrind. */ + char *valgrind_log; + /* Leak output from valgrind. */ char *leak_info; diff --git a/tools/ccanlint/tests/tests_pass.c b/tools/ccanlint/tests/tests_pass.c index 15a97363..15df1ed6 100644 --- a/tools/ccanlint/tests/tests_pass.c +++ b/tools/ccanlint/tests/tests_pass.c @@ -14,18 +14,77 @@ #include #include #include +#include "tests_pass.h" + +bool do_valgrind = false; static const char *can_run(struct manifest *m) { + unsigned int timeleft = default_timeout_ms; + char *output; if (safe_mode) return "Safe mode enabled"; + + if (!is_excluded("tests_pass_valgrind") + && run_command(m, &timeleft, &output, + "valgrind -q true")) + do_valgrind = true; + return NULL; } -static void do_run_tests(struct manifest *m, - bool keep, - unsigned int *timeleft, - struct score *score) +static const char *concat(struct score *score, char *bits[]) +{ + unsigned int i; + char *ret = talloc_strdup(score, ""); + + for (i = 0; bits[i]; i++) { + if (i) + ret = talloc_append_string(ret, " "); + ret = talloc_append_string(ret, bits[i]); + } + return ret; +} + +static bool run_test(void *ctx, + struct manifest *m, + unsigned int *timeleft, char **cmdout, + struct ccan_file *i, + bool use_valgrind) +{ + if (use_valgrind) { + const char *options; + options = concat(ctx, + per_file_options(&tests_pass_valgrind, i)); + + if (!streq(options, "FAIL")) { + /* FIXME: Valgrind's output sucks. XML is + * unreadable by humans *and* doesn't support + * children reporting. */ + i->valgrind_log = talloc_asprintf(m, + "%s.valgrind-log", + i->compiled); + talloc_set_destructor(i->valgrind_log, + unlink_file_destructor); + + return run_command(ctx, timeleft, cmdout, + "valgrind -q" + " --leak-check=full" + " --log-fd=3 %s %s" + " 3> %s", + options, + i->compiled, i->valgrind_log); + } + } + + return run_command(m, timeleft, cmdout, "%s", i->compiled); +} + +static void run_tests(struct manifest *m, + bool keep, + unsigned int *timeleft, + struct score *score, + bool use_valgrind) { struct list_head *list; struct ccan_file *i; @@ -35,8 +94,8 @@ static void do_run_tests(struct manifest *m, foreach_ptr(list, &m->run_tests, &m->api_tests) { list_for_each(list, i, list) { score->total++; - if (run_command(m, timeleft, &cmdout, "%s", - i->compiled)) + if (run_test(score, m, timeleft, &cmdout, i, + use_valgrind)) score->score++; else score_file_error(score, i, 0, "%s", cmdout); @@ -47,6 +106,22 @@ static void do_run_tests(struct manifest *m, score->pass = true; } +static void do_run_tests(struct manifest *m, + bool keep, + unsigned int *timeleft, + struct score *score) +{ + run_tests(m, keep, timeleft, score, do_valgrind); +} + +static void do_run_tests_without_features(struct manifest *m, + bool keep, + unsigned int *timeleft, + struct score *score) +{ + run_tests(m, keep, timeleft, score, false); +} + /* Gcc's warn_unused_result is fascist bullshit. */ #define doesnt_matter() @@ -55,11 +130,12 @@ static void run_under_debugger(struct manifest *m, struct score *score) char *command; struct file_error *first; + first = list_top(&score->per_file_errors, struct file_error, list); + if (!ask("Should I run the first failing test under the debugger?")) return; - first = list_top(&score->per_file_errors, struct file_error, list); - command = talloc_asprintf(m, "gdb -ex 'break tap.c:132' -ex 'run' %s", + command = talloc_asprintf(m, "gdb -ex 'break tap.c:139' -ex 'run' %s", first->file->compiled); if (system(command)) doesnt_matter(); @@ -79,7 +155,7 @@ REGISTER_TEST(tests_pass); struct ccanlint tests_pass_without_features = { .key = "tests_pass_without_features", .name = "Module's run and api tests pass (without features)", - .check = do_run_tests, + .check = do_run_tests_without_features, .handle = run_under_debugger, .needs = "tests_compile_without_features" }; diff --git a/tools/ccanlint/tests/tests_pass.h b/tools/ccanlint/tests/tests_pass.h new file mode 100644 index 00000000..bbf2b36f --- /dev/null +++ b/tools/ccanlint/tests/tests_pass.h @@ -0,0 +1,4 @@ +/* Set in tests_pass. */ +extern bool do_valgrind; + +extern struct ccanlint tests_pass_valgrind; diff --git a/tools/ccanlint/tests/tests_pass_valgrind.c b/tools/ccanlint/tests/tests_pass_valgrind.c index 2a227c88..64cb29e2 100644 --- a/tools/ccanlint/tests/tests_pass_valgrind.c +++ b/tools/ccanlint/tests/tests_pass_valgrind.c @@ -5,6 +5,7 @@ #include #include #include +#include "tests_pass.h" #include #include #include @@ -23,12 +24,8 @@ REGISTER_TEST(tests_pass_valgrind_noleaks); /* Note: we already test safe_mode in run_tests.c */ static const char *can_run_vg(struct manifest *m) { - unsigned int timeleft = default_timeout_ms; - char *output; - - if (!run_command(m, &timeleft, &output, - "valgrind -q --error-exitcode=0 true")) - return talloc_asprintf(m, "No valgrind support: %s", output); + if (!do_valgrind) + return talloc_asprintf(m, "No valgrind support"); return NULL; } @@ -149,21 +146,19 @@ static const char *concat(struct score *score, char *bits[]) /* FIXME: Run examples, too! */ static void do_run_tests_vg(struct manifest *m, - bool keep, + bool keep, unsigned int *timeleft, struct score *score) { struct ccan_file *i; struct list_head *list; - char *cmdout; /* This is slow, so we run once but grab leak info. */ score->total = 0; score->pass = true; foreach_ptr(list, &m->run_tests, &m->api_tests) { list_for_each(list, i, list) { - char *output, *err, *log; - bool pass; + char *err, *output; const char *options; score->total++; @@ -173,31 +168,13 @@ static void do_run_tests_vg(struct manifest *m, if (streq(options, "FAIL")) continue; - /* FIXME: Valgrind's output sucks. XML is unreadable by - * humans *and* doesn't support children reporting. */ - log = talloc_asprintf(score, - "%s.valgrind-log", i->compiled); - if (!keep) - talloc_set_destructor(log, - unlink_file_destructor); - - pass = run_command(score, timeleft, &cmdout, - "valgrind -q --error-exitcode=101" - " --leak-check=full" - " --log-fd=3 %s %s" - " 3> %s", - options, - i->compiled, log); - output = grab_file(i, log, NULL); - /* No valgrind errors? Expect it to pass... */ + if (keep) + talloc_set_destructor(i->valgrind_log, NULL); + + output = grab_file(i, i->valgrind_log, NULL); + /* No valgrind errors? */ if (!output || output[0] == '\0') { - if (!pass) { - err = talloc_asprintf(score, - "Test failed:\n" - "%s", - cmdout); - } else - err = NULL; + err = NULL; i->leak_info = NULL; } else { i->leak_info = analyze_output(output, &err);