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