]> git.ipfire.org Git - thirdparty/kmod.git/blob - testsuite/testsuite.c
testsuite: move oneshot to inside the test struct
[thirdparty/kmod.git] / testsuite / testsuite.c
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <getopt.h>
4 #include <limits.h>
5 #include <stdio.h>
6 #include <stdarg.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <sys/prctl.h>
11 #include <sys/wait.h>
12
13 #include "testsuite.h"
14
15 static const char *progname;
16 static int oneshot = 0;
17 static const char options_short[] = "lhn";
18 static const struct option options[] = {
19 { "list", no_argument, 0, 'l' },
20 { "help", no_argument, 0, 'h' },
21 { NULL, 0, 0, 0 }
22 };
23
24 static void help(void)
25 {
26 const struct option *itr;
27 const char *itr_short;
28
29 printf("Usage:\n"
30 "\t%s [options] <test>\n"
31 "Options:\n", basename(progname));
32
33 for (itr = options, itr_short = options_short;
34 itr->name != NULL; itr++, itr_short++)
35 printf("\t-%c, --%s\n", *itr_short, itr->name);
36 }
37
38 static void test_list(const struct test *tests[])
39 {
40 size_t i;
41
42 printf("Available tests:\n");
43 for (i = 0; tests[i] != NULL; i++)
44 printf("\t%s, %s\n", tests[i]->name, tests[i]->description);
45 }
46
47 int test_init(int argc, char *const argv[], const struct test *tests[])
48 {
49 progname = argv[0];
50
51 for (;;) {
52 int c, idx = 0;
53 c = getopt_long(argc, argv, options_short, options, &idx);
54 if (c == -1)
55 break;
56 switch (c) {
57 case 'l':
58 test_list(tests);
59 return 0;
60 case 'h':
61 help();
62 return 0;
63 case 'n':
64 oneshot = 1;
65 break;
66 case '?':
67 return -1;
68 default:
69 ERR("unexpected getopt_long() value %c\n", c);
70 return -1;
71 }
72 }
73
74 return optind;
75 }
76
77 const struct test *test_find(const struct test *tests[], const char *name)
78 {
79 size_t i;
80
81 for (i = 0; tests[i] != NULL; i++) {
82 if (strcmp(tests[i]->name, name) == 0)
83 return tests[i];
84 }
85
86 return NULL;
87 }
88
89 static int test_spawn_test(const struct test *t)
90 {
91 const char *const args[] = { progname, "-n", t->name, NULL };
92
93 execv(progname, (char *const *) args);
94
95 ERR("failed to spawn %s for %s: %m\n", progname, t->name);
96 return EXIT_FAILURE;
97 }
98
99 static int test_run_spawned(const struct test *t)
100 {
101 int err = t->func(t);
102 exit(err);
103
104 return EXIT_FAILURE;
105 }
106
107 int test_spawn_prog(const char *prog, const char *args[])
108 {
109 execv(prog, (char *const *) args);
110
111 ERR("failed to spawn %s ", prog);
112 return EXIT_FAILURE;
113 }
114
115 {
116 }
117
118 int test_run(const struct test *t)
119 {
120 int err;
121 pid_t pid;
122
123 if (t->need_spawn && oneshot)
124 test_run_spawned(t);
125
126 LOG("running %s, in forked context\n", t->name);
127
128 pid = fork();
129 if (pid < 0) {
130 ERR("could not fork(): %m\n");
131 LOG("FAILED: %s\n", t->name);
132 return EXIT_FAILURE;
133 }
134
135 if (pid > 0) {
136 do {
137 pid = wait(&err);
138 if (pid == -1) {
139 ERR("error waitpid(): %m\n");
140 return EXIT_FAILURE;
141 }
142 } while (!WIFEXITED(err) && !WIFSIGNALED(err));
143
144 if (err != 0)
145 ERR("error while running %s\n", t->name);
146
147 LOG("%s: %s\n", err == 0 ? "PASSED" : "FAILED", t->name);
148 return err;
149 }
150
151 /* kill child if parent dies */
152 prctl(PR_SET_PDEATHSIG, SIGTERM);
153
154 if (t->need_spawn)
155 return test_spawn_test(t);
156 else
157 return test_run_spawned(t);
158 }