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>