1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
It is considered beerware. Prost. Skol. Cheers or whatever.
$id$ */
/* System */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
/* 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();
}
|