Merge branch 'fetcher-response-code'
[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 * Flag to indicate if a worker thread failed
45 */
46 static bool worker_failed;
47
48 /**
49 * Longjump restore point when failing
50 */
51 sigjmp_buf test_restore_point_env;
52
53 /**
54 * See header.
55 */
56 test_suite_t* test_suite_create(const char *name)
57 {
58 test_suite_t *suite;
59
60 INIT(suite,
61 .name = name,
62 .tcases = array_create(0, 0),
63 );
64 return suite;
65 }
66
67 /**
68 * See header.
69 */
70 test_case_t* test_case_create(const char *name)
71 {
72 test_case_t *tcase;
73
74 INIT(tcase,
75 .name = name,
76 .functions = array_create(sizeof(test_function_t), 0),
77 .fixtures = array_create(sizeof(test_fixture_t), 0),
78 .timeout = TEST_FUNCTION_DEFAULT_TIMEOUT,
79 );
80 return tcase;
81 }
82
83 /**
84 * See header.
85 */
86 void test_case_add_checked_fixture(test_case_t *tcase, test_fixture_cb_t setup,
87 test_fixture_cb_t teardown)
88 {
89 test_fixture_t fixture = {
90 .setup = setup,
91 .teardown = teardown,
92 };
93 array_insert(tcase->fixtures, -1, &fixture);
94 }
95
96 /**
97 * See header.
98 */
99 void test_case_add_test_name(test_case_t *tcase, char *name,
100 test_function_cb_t cb, int start, int end)
101 {
102 test_function_t fun = {
103 .name = name,
104 .cb = cb,
105 .start = start,
106 .end = end,
107 };
108 array_insert(tcase->functions, -1, &fun);
109 }
110
111 /**
112 * See header.
113 */
114 void test_case_set_timeout(test_case_t *tcase, int s)
115 {
116 tcase->timeout = s;
117 }
118
119 /**
120 * See header.
121 */
122 void test_suite_add_case(test_suite_t *suite, test_case_t *tcase)
123 {
124 array_insert(suite->tcases, -1, tcase);
125 }
126
127 /**
128 * Main thread performing tests
129 */
130 static pthread_t main_thread;
131
132 /**
133 * Let test case fail
134 */
135 static inline void test_failure()
136 {
137 if (pthread_self() == main_thread)
138 {
139 siglongjmp(test_restore_point_env, 1);
140 }
141 else
142 {
143 pthread_kill(main_thread, SIGUSR1);
144 /* terminate thread to prevent it from going wild */
145 pthread_exit(NULL);
146 }
147 }
148
149 /**
150 * See header.
151 */
152 void test_fail_vmsg(const char *file, int line, char *fmt, va_list args)
153 {
154 vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
155 failure_line = line;
156 failure_file = file;
157
158 test_failure();
159 }
160
161 /**
162 * See header.
163 */
164 void test_fail_msg(const char *file, int line, char *fmt, ...)
165 {
166 va_list args;
167
168 va_start(args, fmt);
169 vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
170 failure_line = line;
171 failure_file = file;
172 va_end(args);
173
174 test_failure();
175 }
176
177 /**
178 * See header.
179 */
180 void test_fail_if_worker_failed()
181 {
182 if (pthread_self() == main_thread && worker_failed)
183 {
184 test_failure();
185 }
186 }
187
188 /**
189 * Signal handler catching critical and alarm signals
190 */
191 static void test_sighandler(int signal)
192 {
193 char *signame;
194 bool old = FALSE;
195
196 switch (signal)
197 {
198 case SIGUSR1:
199 /* a different thread failed, abort test at the next opportunity */
200 worker_failed = TRUE;
201 return;
202 case SIGSEGV:
203 signame = "SIGSEGV";
204 break;
205 case SIGILL:
206 signame = "SIGILL";
207 break;
208 case SIGBUS:
209 signame = "SIGBUS";
210 break;
211 case SIGALRM:
212 signame = "timeout";
213 break;
214 default:
215 signame = "SIG";
216 break;
217 }
218 if (lib->leak_detective)
219 {
220 old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
221 }
222 failure_backtrace = backtrace_create(3);
223 if (lib->leak_detective)
224 {
225 lib->leak_detective->set_state(lib->leak_detective, old);
226 }
227 test_fail_msg(NULL, 0, "%s(%d)", signame, signal);
228 /* unable to restore a valid context for that thread, terminate */
229 fprintf(stderr, "\n%s(%d) outside of main thread:\n", signame, signal);
230 failure_backtrace->log(failure_backtrace, stderr, TRUE);
231 fprintf(stderr, "terminating...\n");
232 abort();
233 }
234
235 /**
236 * See header.
237 */
238 void test_setup_handler()
239 {
240 struct sigaction action = {
241 .sa_handler = test_sighandler,
242 };
243
244 main_thread = pthread_self();
245
246 /* signal handler inherited by all threads */
247 sigaction(SIGSEGV, &action, NULL);
248 sigaction(SIGILL, &action, NULL);
249 sigaction(SIGBUS, &action, NULL);
250 /* ignore ALRM/USR1, these are catched by main thread only */
251 action.sa_handler = SIG_IGN;
252 sigaction(SIGALRM, &action, NULL);
253 sigaction(SIGUSR1, &action, NULL);
254 }
255
256 /**
257 * See header.
258 */
259 void test_setup_timeout(int s)
260 {
261 struct sigaction action = {
262 .sa_handler = test_sighandler,
263 };
264
265 /* This called by main thread only. Setup handler for timeout and
266 * failure cross-thread signaling. */
267 sigaction(SIGALRM, &action, NULL);
268 sigaction(SIGUSR1, &action, NULL);
269
270 alarm(s);
271
272 worker_failed = FALSE;
273 }
274
275 /**
276 * See header.
277 */
278 int test_failure_get(char *msg, int len, const char **file)
279 {
280 strncpy(msg, failure_buf, len - 1);
281 msg[len - 1] = 0;
282 *file = failure_file;
283 return failure_line;
284 }
285
286 /**
287 * See header.
288 */
289 backtrace_t *test_failure_backtrace()
290 {
291 backtrace_t *bt;
292
293 bt = failure_backtrace;
294 failure_backtrace = NULL;
295
296 return bt;
297 }