Annotation of embedaddon/strongswan/src/libstrongswan/tests/test_suite.c, revision 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>