File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / tests / test_suite.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:43 2020 UTC (4 years, 3 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    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>