ccanlint: run tests in parallel
[ccan] / tools / ccanlint / tests / tests_pass.c
1 #include <tools/ccanlint/ccanlint.h>
2 #include <tools/tools.h>
3 #include <ccan/talloc/talloc.h>
4 #include <ccan/str/str.h>
5 #include <ccan/foreach/foreach.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <limits.h>
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <err.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include "tests_pass.h"
18
19 bool do_valgrind = false;
20
21 static const char *can_run(struct manifest *m)
22 {
23         unsigned int timeleft = default_timeout_ms;
24         char *output;
25         if (safe_mode)
26                 return "Safe mode enabled";
27
28         if (!is_excluded("tests_pass_valgrind")
29             && run_command(m, &timeleft, &output,
30                            "valgrind -q true"))
31                 do_valgrind = true;
32
33         return NULL;
34 }
35
36 static const char *concat(struct score *score, char *bits[])
37 {
38         unsigned int i;
39         char *ret = talloc_strdup(score, "");
40
41         for (i = 0; bits[i]; i++) {
42                 if (i)
43                         ret = talloc_append_string(ret, " ");
44                 ret = talloc_append_string(ret, bits[i]);
45         }
46         return ret;
47 }
48
49 static void run_test(void *ctx,
50                      struct manifest *m,
51                      unsigned int *timeleft,
52                      struct ccan_file *i)
53 {
54         if (do_valgrind) {
55                 const char *options;
56                 options = concat(ctx,
57                                  per_file_options(&tests_pass_valgrind, i));
58
59                 if (!streq(options, "FAIL")) {
60                         /* FIXME: Valgrind's output sucks.  XML is
61                          * unreadable by humans *and* doesn't support
62                          * children reporting. */
63                         i->valgrind_log = talloc_asprintf(m,
64                                           "%s.valgrind-log",
65                                           i->compiled[COMPILE_NORMAL]);
66                         talloc_set_destructor(i->valgrind_log,
67                                               unlink_file_destructor);
68
69                         run_command_async(i, *timeleft,
70                                           "valgrind -q"
71                                           " --leak-check=full"
72                                           " --log-fd=3 %s %s"
73                                           " 3> %s",
74                                           options,
75                                           i->compiled[COMPILE_NORMAL],
76                                           i->valgrind_log);
77                         return;
78                 }
79         }
80
81         run_command_async(i, *timeleft, "%s",
82                           i->compiled[COMPILE_NORMAL]);
83 }
84
85 static void do_run_tests(struct manifest *m,
86                          bool keep,
87                          unsigned int *timeleft,
88                          struct score *score)
89 {
90         struct list_head *list;
91         struct ccan_file *i;
92         char *cmdout;
93         bool ok;
94
95         score->total = 0;
96         foreach_ptr(list, &m->run_tests, &m->api_tests) {
97                 list_for_each(list, i, list) {
98                         score->total++;
99                         if (verbose >= 2)
100                                 printf("   %s...\n", i->name);
101                         run_test(score, m, timeleft, i);
102                 }
103         }
104
105         while ((i = collect_command(&ok, &cmdout)) != NULL) {
106                 if (!ok)
107                         score_file_error(score, i, 0, "%s", cmdout);
108                 else
109                         score->score++;
110                 if (verbose >= 2)
111                         printf("   ...%s\n", i->name);
112         }
113
114         if (score->score == score->total)
115                 score->pass = true;
116 }
117
118
119 /* Gcc's warn_unused_result is fascist bullshit. */
120 #define doesnt_matter()
121
122 static void run_under_debugger(struct manifest *m, struct score *score)
123 {
124         char *command;
125         struct file_error *first;
126
127         first = list_top(&score->per_file_errors, struct file_error, list);
128
129         if (!ask("Should I run the first failing test under the debugger?"))
130                 return;
131
132         command = talloc_asprintf(m, "gdb -ex 'break tap.c:139' -ex 'run' %s",
133                                   first->file->compiled[COMPILE_NORMAL]);
134         if (system(command))
135                 doesnt_matter();
136 }
137
138 struct ccanlint tests_pass = {
139         .key = "tests_pass",
140         .name = "Module's run and api tests pass",
141         .check = do_run_tests,
142         .handle = run_under_debugger,
143         .can_run = can_run,
144         .needs = "tests_compile"
145 };
146
147 REGISTER_TEST(tests_pass);