]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/tests/test_suite.c
00ac31830a7252d0b6cbd1289101997924651ffe
[people/ms/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 #ifndef WIN32
22 #include <pthread.h>
23 #endif
24
25 #include <threading/thread.h>
26
27 /**
28 * Failure message buf
29 */
30 static char failure_buf[512];
31
32 /**
33 * Source file failure occurred
34 */
35 static const char *failure_file;
36
37 /**
38 * Line of source file failure occurred
39 */
40 static int failure_line;
41
42 /**
43 * Backtrace of failure, if any
44 */
45 static backtrace_t *failure_backtrace;
46
47 /**
48 * Flag to indicate if a worker thread failed
49 */
50 static bool worker_failed;
51
52 /**
53 * See header.
54 */
55 test_suite_t* test_suite_create(const char *name)
56 {
57 test_suite_t *suite;
58
59 INIT(suite,
60 .name = name,
61 .tcases = array_create(0, 0),
62 );
63 return suite;
64 }
65
66 /**
67 * See header.
68 */
69 test_case_t* test_case_create(const char *name)
70 {
71 test_case_t *tcase;
72
73 INIT(tcase,
74 .name = name,
75 .functions = array_create(sizeof(test_function_t), 0),
76 .fixtures = array_create(sizeof(test_fixture_t), 0),
77 .timeout = TEST_FUNCTION_DEFAULT_TIMEOUT,
78 );
79 return tcase;
80 }
81
82 /**
83 * See header.
84 */
85 void test_case_add_checked_fixture(test_case_t *tcase, test_fixture_cb_t setup,
86 test_fixture_cb_t teardown)
87 {
88 test_fixture_t fixture = {
89 .setup = setup,
90 .teardown = teardown,
91 };
92 array_insert(tcase->fixtures, -1, &fixture);
93 }
94
95 /**
96 * See header.
97 */
98 void test_case_add_test_name(test_case_t *tcase, char *name,
99 test_function_cb_t cb, int start, int end)
100 {
101 test_function_t fun = {
102 .name = name,
103 .cb = cb,
104 .start = start,
105 .end = end,
106 };
107 array_insert(tcase->functions, -1, &fun);
108 }
109
110 /**
111 * See header.
112 */
113 void test_case_set_timeout(test_case_t *tcase, int s)
114 {
115 tcase->timeout = s;
116 }
117
118 /**
119 * See header.
120 */
121 void test_suite_add_case(test_suite_t *suite, test_case_t *tcase)
122 {
123 array_insert(suite->tcases, -1, tcase);
124 }
125
126 #ifdef WIN32
127
128 /**
129 * Longjump restore point when failing
130 */
131 jmp_buf test_restore_point_env;
132
133 /**
134 * Thread ID of main thread
135 */
136 static DWORD main_thread;
137
138 /**
139 * APC routine invoked by main thread on worker failure
140 */
141 static void WINAPI set_worker_failure(ULONG_PTR dwParam)
142 {
143 worker_failed = TRUE;
144 }
145
146 /**
147 * Let test case fail
148 */
149 static void test_failure()
150 {
151 if (GetCurrentThreadId() == main_thread)
152 {
153 longjmp(test_restore_point_env, 1);
154 }
155 else
156 {
157 HANDLE *thread;
158
159 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, main_thread);
160 if (thread)
161 {
162 QueueUserAPC(set_worker_failure, thread, (uintptr_t)NULL);
163 CloseHandle(thread);
164 }
165 thread_exit(NULL);
166 }
167 }
168
169 /**
170 * See header.
171 */
172 void test_fail_if_worker_failed()
173 {
174 if (GetCurrentThreadId() == main_thread && worker_failed)
175 {
176 test_failure();
177 }
178 }
179
180 /**
181 * Vectored exception handler
182 */
183 static long WINAPI eh_handler(PEXCEPTION_POINTERS ei)
184 {
185 char *ename;
186 bool old = FALSE;
187
188 switch (ei->ExceptionRecord->ExceptionCode)
189 {
190 case EXCEPTION_ACCESS_VIOLATION:
191 ename = "ACCESS_VIOLATION";
192 break;
193 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
194 ename = "ARRAY_BOUNDS_EXCEEDED";
195 break;
196 case EXCEPTION_DATATYPE_MISALIGNMENT:
197 ename = "DATATYPE_MISALIGNMENT";
198 break;
199 case EXCEPTION_FLT_DENORMAL_OPERAND:
200 ename = "FLT_DENORMAL_OPERAND";
201 break;
202 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
203 ename = "FLT_DIVIDE_BY_ZERO";
204 break;
205 case EXCEPTION_FLT_INEXACT_RESULT:
206 ename = "FLT_INEXACT_RESULT";
207 break;
208 case EXCEPTION_FLT_INVALID_OPERATION:
209 ename = "FLT_INVALID_OPERATION";
210 break;
211 case EXCEPTION_FLT_OVERFLOW:
212 ename = "FLT_OVERFLOW";
213 break;
214 case EXCEPTION_FLT_STACK_CHECK:
215 ename = "FLT_STACK_CHECK";
216 break;
217 case EXCEPTION_FLT_UNDERFLOW:
218 ename = "FLT_UNDERFLOW";
219 break;
220 case EXCEPTION_ILLEGAL_INSTRUCTION:
221 ename = "ILLEGAL_INSTRUCTION";
222 break;
223 case EXCEPTION_IN_PAGE_ERROR:
224 ename = "IN_PAGE_ERROR";
225 break;
226 case EXCEPTION_INT_DIVIDE_BY_ZERO:
227 ename = "INT_DIVIDE_BY_ZERO";
228 break;
229 case EXCEPTION_INT_OVERFLOW:
230 ename = "INT_OVERFLOW";
231 break;
232 case EXCEPTION_INVALID_DISPOSITION:
233 ename = "INVALID_DISPOSITION";
234 break;
235 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
236 ename = "NONCONTINUABLE_EXCEPTION";
237 break;
238 case EXCEPTION_PRIV_INSTRUCTION:
239 ename = "PRIV_INSTRUCTION";
240 break;
241 case EXCEPTION_STACK_OVERFLOW:
242 ename = "STACK_OVERFLOW";
243 break;
244 default:
245 return EXCEPTION_CONTINUE_EXECUTION;
246 }
247
248 if (lib->leak_detective)
249 {
250 old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
251 }
252 failure_backtrace = backtrace_create(5);
253 if (lib->leak_detective)
254 {
255 lib->leak_detective->set_state(lib->leak_detective, old);
256 }
257 failure_line = 0;
258 test_fail_msg(NULL, 0, "%s exception", ename);
259 /* not reached */
260 return EXCEPTION_CONTINUE_EXECUTION;
261 }
262
263 /**
264 * See header.
265 */
266 void test_setup_handler()
267 {
268 main_thread = GetCurrentThreadId();
269 AddVectoredExceptionHandler(0, eh_handler);
270 }
271
272 /**
273 * See header.
274 */
275 void test_setup_timeout(int s)
276 {
277 /* TODO: currently not supported. SetTimer()? */
278
279 worker_failed = FALSE;
280 }
281
282 #else /* !WIN32 */
283
284 /**
285 * Longjump restore point when failing
286 */
287 sigjmp_buf test_restore_point_env;
288
289 /**
290 * Main thread performing tests
291 */
292 static pthread_t main_thread;
293
294 /**
295 * Let test case fail
296 */
297 static inline void test_failure()
298 {
299 if (pthread_self() == main_thread)
300 {
301 siglongjmp(test_restore_point_env, 1);
302 }
303 else
304 {
305 pthread_kill(main_thread, SIGUSR1);
306 /* terminate thread to prevent it from going wild */
307 pthread_exit(NULL);
308 }
309 }
310
311 /**
312 * See header.
313 */
314 void test_fail_if_worker_failed()
315 {
316 if (pthread_self() == main_thread && worker_failed)
317 {
318 test_failure();
319 }
320 }
321
322 /**
323 * Signal handler catching critical and alarm signals
324 */
325 static void test_sighandler(int signal)
326 {
327 char *signame;
328 bool old = FALSE;
329
330 switch (signal)
331 {
332 case SIGUSR1:
333 /* a different thread failed, abort test at the next opportunity */
334 worker_failed = TRUE;
335 return;
336 case SIGSEGV:
337 signame = "SIGSEGV";
338 break;
339 case SIGILL:
340 signame = "SIGILL";
341 break;
342 case SIGBUS:
343 signame = "SIGBUS";
344 break;
345 case SIGALRM:
346 signame = "timeout";
347 break;
348 default:
349 signame = "SIG";
350 break;
351 }
352 if (lib->leak_detective)
353 {
354 old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
355 }
356 failure_backtrace = backtrace_create(3);
357 if (lib->leak_detective)
358 {
359 lib->leak_detective->set_state(lib->leak_detective, old);
360 }
361 test_fail_msg(NULL, 0, "%s(%d)", signame, signal);
362 /* unable to restore a valid context for that thread, terminate */
363 fprintf(stderr, "\n%s(%d) outside of main thread:\n", signame, signal);
364 failure_backtrace->log(failure_backtrace, stderr, TRUE);
365 fprintf(stderr, "terminating...\n");
366 abort();
367 }
368
369 /**
370 * See header.
371 */
372 void test_setup_handler()
373 {
374 struct sigaction action = {
375 .sa_handler = test_sighandler,
376 };
377
378 main_thread = pthread_self();
379
380 /* signal handler inherited by all threads */
381 sigaction(SIGSEGV, &action, NULL);
382 sigaction(SIGILL, &action, NULL);
383 sigaction(SIGBUS, &action, NULL);
384 /* ignore ALRM/USR1, these are catched by main thread only */
385 action.sa_handler = SIG_IGN;
386 sigaction(SIGALRM, &action, NULL);
387 sigaction(SIGUSR1, &action, NULL);
388 }
389
390 /**
391 * See header.
392 */
393 void test_setup_timeout(int s)
394 {
395 struct sigaction action = {
396 .sa_handler = test_sighandler,
397 };
398
399 /* This called by main thread only. Setup handler for timeout and
400 * failure cross-thread signaling. */
401 sigaction(SIGALRM, &action, NULL);
402 sigaction(SIGUSR1, &action, NULL);
403
404 alarm(s);
405
406 worker_failed = FALSE;
407 }
408
409 #endif /* !WIN32 */
410
411 /**
412 * See header.
413 */
414 void test_fail_vmsg(const char *file, int line, char *fmt, va_list args)
415 {
416 vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
417 failure_line = line;
418 failure_file = file;
419
420 test_failure();
421 }
422 /**
423 * See header.
424 */
425 void test_fail_msg(const char *file, int line, char *fmt, ...)
426 {
427 va_list args;
428
429 va_start(args, fmt);
430 vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
431 failure_line = line;
432 failure_file = file;
433 va_end(args);
434
435 test_failure();
436 }
437
438 /**
439 * See header.
440 */
441 int test_failure_get(char *msg, int len, const char **file)
442 {
443 strncpy(msg, failure_buf, len - 1);
444 msg[len - 1] = 0;
445 *file = failure_file;
446 return failure_line;
447 }
448
449 /**
450 * See header.
451 */
452 backtrace_t *test_failure_backtrace()
453 {
454 backtrace_t *bt;
455
456 bt = failure_backtrace;
457 failure_backtrace = NULL;
458
459 return bt;
460 }