unit-tests: Don't assert failures for unreadable settings files as root
[strongswan.git] / src / libstrongswan / tests / test_suite.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "test_suite.h"
17
18 #include <signal.h>
19 #include <unistd.h>
20
21 #include <pthread.h>
22
23 /**
24 * Failure message buf
25 */
26 static char failure_buf[512];
27
28 /**
29 * Source file failure occurred
30 */
31 static const char *failure_file;
32
33 /**
34 * Line of source file failure occurred
35 */
36 static int failure_line;
37
38 /**
39 * Backtrace of failure, if any
40 */
41 static backtrace_t *failure_backtrace;
42
43 /**
44 * Longjump restore point when failing
45 */
46 sigjmp_buf test_restore_point_env;
47
48 /**
49 * See header.
50 */
51 test_suite_t* test_suite_create(const char *name)
52 {
53 test_suite_t *suite;
54
55 INIT(suite,
56 .name = name,
57 .tcases = array_create(0, 0),
58 );
59 return suite;
60 }
61
62 /**
63 * See header.
64 */
65 test_case_t* test_case_create(const char *name)
66 {
67 test_case_t *tcase;
68
69 INIT(tcase,
70 .name = name,
71 .functions = array_create(sizeof(test_function_t), 0),
72 .fixtures = array_create(sizeof(test_fixture_t), 0),
73 .timeout = TEST_FUNCTION_DEFAULT_TIMEOUT,
74 );
75 return tcase;
76 }
77
78 /**
79 * See header.
80 */
81 void test_case_add_checked_fixture(test_case_t *tcase, test_fixture_cb_t setup,
82 test_fixture_cb_t teardown)
83 {
84 test_fixture_t fixture = {
85 .setup = setup,
86 .teardown = teardown,
87 };
88 array_insert(tcase->fixtures, -1, &fixture);
89 }
90
91 /**
92 * See header.
93 */
94 void test_case_add_test_name(test_case_t *tcase, char *name,
95 test_function_cb_t cb, int start, int end)
96 {
97 test_function_t fun = {
98 .name = name,
99 .cb = cb,
100 .start = start,
101 .end = end,
102 };
103 array_insert(tcase->functions, -1, &fun);
104 }
105
106 /**
107 * See header.
108 */
109 void test_case_set_timeout(test_case_t *tcase, int s)
110 {
111 tcase->timeout = s;
112 }
113
114 /**
115 * See header.
116 */
117 void test_suite_add_case(test_suite_t *suite, test_case_t *tcase)
118 {
119 array_insert(suite->tcases, -1, tcase);
120 }
121
122 /**
123 * Main thread performing tests
124 */
125 static pthread_t main_thread;
126
127 /**
128 * Let test case fail
129 */
130 static inline void test_failure()
131 {
132 if (pthread_self() == main_thread)
133 {
134 siglongjmp(test_restore_point_env, 1);
135 }
136 else
137 {
138 pthread_kill(main_thread, SIGUSR1);
139 /* terminate thread to prevent it from going wild */
140 pthread_exit(NULL);
141 }
142 }
143
144 /**
145 * See header.
146 */
147 void test_fail_vmsg(const char *file, int line, char *fmt, va_list args)
148 {
149 vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
150 failure_line = line;
151 failure_file = file;
152
153 test_failure();
154 }
155
156 /**
157 * See header.
158 */
159 void test_fail_msg(const char *file, int line, char *fmt, ...)
160 {
161 va_list args;
162
163 va_start(args, fmt);
164 vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
165 failure_line = line;
166 failure_file = file;
167 va_end(args);
168
169 test_failure();
170 }
171
172 /**
173 * Signal handler catching critical and alarm signals
174 */
175 static void test_sighandler(int signal)
176 {
177 char *signame;
178 bool old = FALSE;
179
180 switch (signal)
181 {
182 case SIGUSR1:
183 /* a different thread failed, abort test */
184 return test_failure();
185 case SIGSEGV:
186 signame = "SIGSEGV";
187 break;
188 case SIGILL:
189 signame = "SIGILL";
190 break;
191 case SIGBUS:
192 signame = "SIGBUS";
193 break;
194 case SIGALRM:
195 signame = "timeout";
196 break;
197 default:
198 signame = "SIG";
199 break;
200 }
201 if (lib->leak_detective)
202 {
203 old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
204 }
205 failure_backtrace = backtrace_create(3);
206 if (lib->leak_detective)
207 {
208 lib->leak_detective->set_state(lib->leak_detective, old);
209 }
210 test_fail_msg(NULL, 0, "%s(%d)", signame, signal);
211 /* unable to restore a valid context for that thread, terminate */
212 fprintf(stderr, "\n%s(%d) outside of main thread:\n", signame, signal);
213 failure_backtrace->log(failure_backtrace, stderr, TRUE);
214 fprintf(stderr, "terminating...\n");
215 abort();
216 }
217
218 /**
219 * See header.
220 */
221 void test_setup_handler()
222 {
223 struct sigaction action = {
224 .sa_handler = test_sighandler,
225 };
226
227 main_thread = pthread_self();
228
229 /* signal handler inherited by all threads */
230 sigaction(SIGSEGV, &action, NULL);
231 sigaction(SIGILL, &action, NULL);
232 sigaction(SIGBUS, &action, NULL);
233 /* ignore ALRM/USR1, these are catched by main thread only */
234 action.sa_handler = SIG_IGN;
235 sigaction(SIGALRM, &action, NULL);
236 sigaction(SIGUSR1, &action, NULL);
237 }
238
239 /**
240 * See header.
241 */
242 void test_setup_timeout(int s)
243 {
244 struct sigaction action = {
245 .sa_handler = test_sighandler,
246 };
247
248 /* This called by main thread only. Setup handler for timeout and
249 * failure cross-thread signaling. */
250 sigaction(SIGALRM, &action, NULL);
251 sigaction(SIGUSR1, &action, NULL);
252
253 alarm(s);
254 }
255
256 /**
257 * See header.
258 */
259 int test_failure_get(char *msg, int len, const char **file)
260 {
261 strncpy(msg, failure_buf, len - 1);
262 msg[len - 1] = 0;
263 *file = failure_file;
264 return failure_line;
265 }
266
267 /**
268 * See header.
269 */
270 backtrace_t *test_failure_backtrace()
271 {
272 backtrace_t *bt;
273
274 bt = failure_backtrace;
275 failure_backtrace = NULL;
276
277 return bt;
278 }