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