Annotation of embedaddon/strongswan/src/libstrongswan/tests/test_runner.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2013 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  * Copyright (C) 2013 Martin Willi
                      5:  * Copyright (C) 2013 revosec AG
                      6:  *
                      7:  * This program is free software; you can redistribute it and/or modify it
                      8:  * under the terms of the GNU General Public License as published by the
                      9:  * Free Software Foundation; either version 2 of the License, or (at your
                     10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     11:  *
                     12:  * This program is distributed in the hope that it will be useful, but
                     13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     15:  * for more details.
                     16:  */
                     17: 
                     18: #include "test_runner.h"
                     19: 
                     20: #include <library.h>
                     21: #include <threading/thread.h>
                     22: #include <plugins/plugin_feature.h>
                     23: #include <collections/array.h>
                     24: #include <utils/test.h>
                     25: 
                     26: #include <stdlib.h>
                     27: #include <dirent.h>
                     28: #include <unistd.h>
                     29: #include <limits.h>
                     30: #include <stdlib.h>
1.1.1.2 ! misho      31: #include <time.h>
1.1       misho      32: 
                     33: /**
                     34:  * Get a tty color escape character for stderr
                     35:  */
                     36: #define TTY(color) tty_escape_get(2, TTY_FG_##color)
                     37: 
                     38: /**
                     39:  * A global symbol indicating libtest linkage
                     40:  */
                     41: #ifdef WIN32
                     42: __declspec(dllexport)
                     43: #endif
                     44: bool test_runner_available = TRUE;
                     45: 
                     46: /**
1.1.1.2 ! misho      47:  * Destroy data associated with a test case.
1.1       misho      48:  */
1.1.1.2 ! misho      49: static void destroy_case(test_case_t *tcase)
1.1       misho      50: {
1.1.1.2 ! misho      51:        array_destroy(tcase->functions);
        !            52:        array_destroy(tcase->fixtures);
        !            53: }
1.1       misho      54: 
1.1.1.2 ! misho      55: /**
        !            56:  * Destroy a single test suite and associated data.
        !            57:  */
        !            58: static void destroy_suite(test_suite_t *suite)
        !            59: {
        !            60:        array_destroy_function(suite->tcases, (void*)destroy_case, NULL);
1.1       misho      61:        free(suite);
                     62: }
                     63: 
                     64: /**
1.1.1.2 ! misho      65:  * Identifies on which component to apply the given filter.
1.1       misho      66:  */
1.1.1.2 ! misho      67: typedef enum {
        !            68:        FILTER_SUITES,
        !            69:        FILTER_CASES,
        !            70:        FILTER_FUNCTIONS,
        !            71: } filter_component_t;
        !            72: 
        !            73: /**
        !            74:  * Check if the component with the given name should be filtered/removed.
        !            75:  */
        !            76: static bool filter_name(const char *name, hashtable_t *names, bool exclude)
1.1       misho      77: {
1.1.1.2 ! misho      78:        return (exclude && names->get(names, name)) ||
        !            79:                   (!exclude && !names->get(names, name));
        !            80: }
        !            81: 
        !            82: /**
        !            83:  * Filter loaded test suites/cases/functions, either remove components listed
        !            84:  * (exclude=TRUE), or all that are not listed (exclude=FALSE).
        !            85:  * Empty test cases/suites are removed and destroyed.
        !            86:  */
        !            87: static void apply_filter(array_t *loaded, filter_component_t comp, char *filter,
        !            88:                                                 bool exclude)
        !            89: {
        !            90:        enumerator_t *enumerator, *tcases, *functions, *names;
1.1       misho      91:        hashtable_t *listed;
                     92:        test_suite_t *suite;
1.1.1.2 ! misho      93:        test_case_t *tcase;
        !            94:        test_function_t *func;
1.1       misho      95:        char *name;
                     96: 
                     97:        listed = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8);
                     98:        names = enumerator_create_token(filter, ",", " ");
                     99:        while (names->enumerate(names, &name))
                    100:        {
                    101:                listed->put(listed, name, name);
                    102:        }
1.1.1.2 ! misho     103: 
1.1       misho     104:        enumerator = array_create_enumerator(loaded);
                    105:        while (enumerator->enumerate(enumerator, &suite))
                    106:        {
1.1.1.2 ! misho     107:                if (comp == FILTER_SUITES)
        !           108:                {
        !           109:                        if (filter_name(suite->name, listed, exclude))
        !           110:                        {
        !           111:                                array_remove_at(loaded, enumerator);
        !           112:                                destroy_suite(suite);
        !           113:                        }
        !           114:                        continue;
        !           115:                }
        !           116:                tcases = array_create_enumerator(suite->tcases);
        !           117:                while (tcases->enumerate(tcases, &tcase))
        !           118:                {
        !           119:                        if (comp == FILTER_CASES)
        !           120:                        {
        !           121:                                if (filter_name(tcase->name, listed, exclude))
        !           122:                                {
        !           123:                                        array_remove_at(suite->tcases, tcases);
        !           124:                                        destroy_case(tcase);
        !           125:                                }
        !           126:                                continue;
        !           127:                        }
        !           128:                        functions = array_create_enumerator(tcase->functions);
        !           129:                        while (functions->enumerate(functions, &func))
        !           130:                        {
        !           131:                                if (filter_name(func->name, listed, exclude))
        !           132:                                {
        !           133:                                        array_remove_at(tcase->functions, functions);
        !           134:                                }
        !           135:                        }
        !           136:                        functions->destroy(functions);
        !           137: 
        !           138:                        if (!array_count(tcase->functions))
        !           139:                        {
        !           140:                                array_remove_at(suite->tcases, tcases);
        !           141:                                destroy_case(tcase);
        !           142:                        }
        !           143:                }
        !           144:                tcases->destroy(tcases);
        !           145: 
        !           146:                if (!array_count(suite->tcases))
1.1       misho     147:                {
                    148:                        array_remove_at(loaded, enumerator);
                    149:                        destroy_suite(suite);
                    150:                }
                    151:        }
                    152:        enumerator->destroy(enumerator);
                    153:        listed->destroy(listed);
                    154:        names->destroy(names);
                    155: }
                    156: 
                    157: /**
                    158:  * Check if the given string is contained in the filter string.
                    159:  */
                    160: static bool is_in_filter(const char *find, char *filter)
                    161: {
                    162:        enumerator_t *names;
                    163:        bool found = FALSE;
                    164:        char *name;
                    165: 
                    166:        names = enumerator_create_token(filter, ",", " ");
                    167:        while (names->enumerate(names, &name))
                    168:        {
                    169:                if (streq(name, find))
                    170:                {
                    171:                        found = TRUE;
                    172:                        break;
                    173:                }
                    174:        }
                    175:        names->destroy(names);
                    176:        return found;
                    177: }
                    178: 
                    179: /**
1.1.1.2 ! misho     180:  * Removes and destroys test suites/cases/functions that are not selected or
        !           181:  * explicitly excluded. Takes names of two environment variables.
1.1       misho     182:  */
1.1.1.2 ! misho     183: static void filter_components(array_t *loaded, filter_component_t comp,
        !           184:                                                          char *sel, char *exc)
1.1       misho     185: {
                    186:        char *filter;
                    187: 
1.1.1.2 ! misho     188:        filter = getenv(sel);
1.1       misho     189:        if (filter)
                    190:        {
1.1.1.2 ! misho     191:                apply_filter(loaded, comp, filter, FALSE);
1.1       misho     192:        }
1.1.1.2 ! misho     193:        filter = getenv(exc);
1.1       misho     194:        if (filter)
                    195:        {
1.1.1.2 ! misho     196:                apply_filter(loaded, comp, filter, TRUE);
1.1       misho     197:        }
                    198: }
                    199: 
                    200: /**
                    201:  * Load all available test suites, or optionally only selected ones.
                    202:  */
                    203: static array_t *load_suites(test_configuration_t configs[],
                    204:                                                        test_runner_init_t init, char *cfg)
                    205: {
                    206:        array_t *suites;
                    207:        bool old = FALSE;
                    208:        int i;
                    209: 
                    210:        library_init(cfg, "test-runner");
                    211: 
                    212:        test_setup_handler();
                    213: 
                    214:        if (init && !init(TRUE))
                    215:        {
                    216:                library_deinit();
                    217:                return NULL;
                    218:        }
                    219:        lib->plugins->status(lib->plugins, LEVEL_CTRL);
                    220: 
                    221:        if (lib->leak_detective)
                    222:        {
                    223:                old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
                    224:        }
                    225: 
                    226:        suites = array_create(0, 0);
                    227: 
                    228:        for (i = 0; configs[i].suite; i++)
                    229:        {
                    230:                if (configs[i].feature.type == 0 ||
                    231:                        lib->plugins->has_feature(lib->plugins, configs[i].feature))
                    232:                {
                    233:                        array_insert(suites, -1, configs[i].suite());
                    234:                }
                    235:        }
1.1.1.2 ! misho     236:        filter_components(suites, FILTER_SUITES, "TESTS_SUITES",
        !           237:                                          "TESTS_SUITES_EXCLUDE");
        !           238:        filter_components(suites, FILTER_CASES, "TESTS_CASES",
        !           239:                                          "TESTS_CASES_EXCLUDE");
        !           240:        filter_components(suites, FILTER_FUNCTIONS, "TESTS_FUNCTIONS",
        !           241:                                          "TESTS_FUNCTIONS_EXCLUDE");
1.1       misho     242: 
                    243:        if (lib->leak_detective)
                    244:        {
                    245:                lib->leak_detective->set_state(lib->leak_detective, old);
                    246:        }
                    247: 
                    248:        if (init)
                    249:        {
                    250:                init(FALSE);
                    251:        }
                    252:        library_deinit();
                    253: 
                    254:        return suites;
                    255: }
                    256: 
                    257: /**
                    258:  * Unload and destroy test suites and associated data
                    259:  */
                    260: static void unload_suites(array_t *suites)
                    261: {
                    262:        test_suite_t *suite;
                    263: 
                    264:        while (array_remove(suites, 0, &suite))
                    265:        {
                    266:                destroy_suite(suite);
                    267:        }
                    268:        array_destroy(suites);
                    269: }
                    270: 
                    271: /**
                    272:  * Run a single test function, return FALSE on failure
                    273:  */
                    274: static bool run_test(test_function_t *tfun, int i)
                    275: {
                    276:        if (test_restore_point())
                    277:        {
                    278:                tfun->cb(i);
                    279:                return TRUE;
                    280:        }
                    281:        thread_cleanup_popall();
                    282:        return FALSE;
                    283: }
                    284: 
                    285: /**
                    286:  * Invoke fixture setup/teardown
                    287:  */
1.1.1.2 ! misho     288: static bool call_fixture(test_case_t *tcase, bool up, int i)
1.1       misho     289: {
                    290:        enumerator_t *enumerator;
                    291:        test_fixture_t *fixture;
                    292:        bool failure = FALSE;
                    293: 
                    294:        enumerator = array_create_enumerator(tcase->fixtures);
                    295:        while (enumerator->enumerate(enumerator, &fixture))
                    296:        {
                    297:                if (test_restore_point())
                    298:                {
                    299:                        if (up)
                    300:                        {
                    301:                                if (fixture->setup)
                    302:                                {
1.1.1.2 ! misho     303:                                        fixture->setup(i);
1.1       misho     304:                                }
                    305:                        }
                    306:                        else
                    307:                        {
                    308:                                if (fixture->teardown)
                    309:                                {
1.1.1.2 ! misho     310:                                        fixture->teardown(i);
1.1       misho     311:                                }
                    312:                        }
                    313:                }
                    314:                else
                    315:                {
                    316:                        thread_cleanup_popall();
                    317:                        failure = TRUE;
                    318:                        break;
                    319:                }
                    320:        }
                    321:        enumerator->destroy(enumerator);
                    322: 
                    323:        return !failure;
                    324: }
                    325: 
                    326: /**
                    327:  * Test initialization, initializes libstrongswan for the next run
                    328:  */
                    329: static bool pre_test(test_runner_init_t init, char *cfg)
                    330: {
                    331:        library_init(cfg, "test-runner");
                    332: 
                    333:        /* use non-blocking RNG to generate keys fast */
                    334:        lib->settings->set_default_str(lib->settings,
                    335:                        "libstrongswan.plugins.random.random",
                    336:                        lib->settings->get_str(lib->settings,
                    337:                                "libstrongswan.plugins.random.urandom", "/dev/urandom"));
                    338:        /* same for the gcrypt plugin */
                    339:        lib->settings->set_default_str(lib->settings,
                    340:                        "libstrongswan.plugins.gcrypt.quick_random", "yes");
                    341: 
                    342:        if (lib->leak_detective)
                    343:        {
                    344:                /* disable leak reports during testing */
                    345:                lib->leak_detective->set_report_cb(lib->leak_detective,
                    346:                                                                                   NULL, NULL, NULL);
                    347:        }
                    348:        if (init && !init(TRUE))
                    349:        {
                    350:                library_deinit();
                    351:                return FALSE;
                    352:        }
                    353:        return TRUE;
                    354: }
                    355: 
                    356: /**
                    357:  * Failure description
                    358:  */
                    359: typedef struct {
                    360:        char *name;
                    361:        char msg[4096 - sizeof(char*) - 2 * sizeof(int)];
                    362:        const char *file;
                    363:        int line;
                    364:        int i;
                    365:        backtrace_t *bt;
                    366: } failure_t;
                    367: 
                    368: /**
                    369:  * Data passed to leak report callbacks
                    370:  */
                    371: typedef struct {
                    372:        array_t *failures;
                    373:        char *name;
                    374:        int i;
                    375:        int leaks;
                    376: } report_data_t;
                    377: 
                    378: /**
                    379:  * Leak report callback, build failures from leaks
                    380:  */
                    381: static void report_leaks(report_data_t *data, int count, size_t bytes,
                    382:                                                 backtrace_t *bt, bool detailed)
                    383: {
                    384:        failure_t failure = {
                    385:                .name = data->name,
                    386:                .i = data->i,
                    387:                .bt = bt->clone(bt),
                    388:        };
                    389: 
                    390:        snprintf(failure.msg, sizeof(failure.msg),
                    391:                         "Leak detected: %d allocations using %zu bytes", count, bytes);
                    392: 
                    393:        array_insert(data->failures, -1, &failure);
                    394: }
                    395: 
                    396: /**
                    397:  * Leak summary callback, check if any leaks found
                    398:  */
                    399: static void sum_leaks(report_data_t *data, int count, size_t bytes,
                    400:                                          int whitelisted)
                    401: {
                    402:        data->leaks = count;
                    403: }
                    404: 
                    405: /**
                    406:  * Do library cleanup and optionally check for memory leaks
                    407:  */
                    408: static bool post_test(test_runner_init_t init, bool check_leaks,
                    409:                                          array_t *failures, char *name, int i, int *leaks)
                    410: {
                    411:        report_data_t data = {
                    412:                .failures = failures,
                    413:                .name = name,
                    414:                .i = i,
                    415:        };
                    416: 
                    417:        if (init)
                    418:        {
                    419:                if (test_restore_point())
                    420:                {
                    421:                        init(FALSE);
                    422:                }
                    423:                else
                    424:                {
                    425:                        thread_cleanup_popall();
                    426:                        library_deinit();
                    427:                        return FALSE;
                    428:                }
                    429:        }
                    430:        if (check_leaks && lib->leak_detective)
                    431:        {
                    432:                lib->leak_detective->set_report_cb(lib->leak_detective,
                    433:                                                                (leak_detective_report_cb_t)report_leaks,
                    434:                                                                (leak_detective_summary_cb_t)sum_leaks, &data);
                    435:        }
                    436:        library_deinit();
                    437: 
                    438:        *leaks = data.leaks;
                    439:        return TRUE;
                    440: }
                    441: 
                    442: /**
                    443:  * Collect failure information, add failure_t to array
                    444:  */
                    445: static void collect_failure_info(array_t *failures, char *name, int i)
                    446: {
                    447:        failure_t failure = {
                    448:                .name = name,
                    449:                .i = i,
                    450:                .bt = test_failure_backtrace(),
                    451:        };
                    452: 
                    453:        failure.line = test_failure_get(failure.msg, sizeof(failure.msg),
                    454:                                                                        &failure.file);
                    455: 
                    456:        array_insert(failures, -1, &failure);
                    457: }
                    458: 
                    459: /**
                    460:  * Collect warning information, add failure_t to array
                    461:  */
                    462: static bool collect_warning_info(array_t *warnings, char *name, int i)
                    463: {
                    464:        failure_t warning = {
                    465:                .name = name,
                    466:                .i = i,
                    467:        };
                    468: 
                    469:        warning.line = test_warning_get(warning.msg, sizeof(warning.msg),
                    470:                                                                        &warning.file);
                    471:        if (warning.line)
                    472:        {
                    473:                array_insert(warnings, -1, &warning);
                    474:        }
                    475:        return warning.line;
                    476: }
                    477: 
                    478: /**
                    479:  * Print array of collected failure_t to stderr
                    480:  */
                    481: static void print_failures(array_t *failures, bool warnings)
                    482: {
                    483:        failure_t failure;
                    484: 
                    485:        threads_init();
                    486:        backtrace_init();
                    487: 
                    488:        while (array_remove(failures, 0, &failure))
                    489:        {
                    490:                if (warnings)
                    491:                {
                    492:                        fprintf(stderr, "      %sWarning in '%s': %s (",
                    493:                                        TTY(YELLOW), failure.name, failure.msg);
                    494:                }
                    495:                else
                    496:                {
                    497:                        fprintf(stderr, "      %sFailure in '%s': %s (",
                    498:                                        TTY(RED), failure.name, failure.msg);
                    499:                }
                    500:                if (failure.line)
                    501:                {
                    502:                        fprintf(stderr, "%s:%d, ", failure.file, failure.line);
                    503:                }
                    504:                fprintf(stderr, "i = %d)%s\n", failure.i, TTY(DEF));
                    505:                if (failure.bt)
                    506:                {
                    507:                        failure.bt->log(failure.bt, stderr, TRUE);
                    508:                        failure.bt->destroy(failure.bt);
                    509:                }
                    510:        }
                    511: 
                    512:        backtrace_deinit();
                    513:        threads_deinit();
                    514: }
                    515: 
1.1.1.2 ! misho     516: #if defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_CLOCK_GETTIME)
        !           517: 
        !           518: /**
        !           519:  * Start a timer
        !           520:  */
        !           521: static void start_timing(struct timespec *start)
        !           522: {
        !           523:        clock_gettime(CLOCK_THREAD_CPUTIME_ID, start);
        !           524: }
        !           525: 
        !           526: /**
        !           527:  * End a timer, return ms
        !           528:  */
        !           529: static double end_timing(struct timespec *start)
        !           530: {
        !           531:        struct timespec end;
        !           532: 
        !           533:        if (!getenv("TESTS_TIMING"))
        !           534:        {
        !           535:                return 0;
        !           536:        }
        !           537:        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
        !           538:        return (end.tv_nsec - start->tv_nsec) / 1000000.0 +
        !           539:                        (end.tv_sec - start->tv_sec) * 1000.0;
        !           540: }
        !           541: 
        !           542: #else /* CLOCK_THREAD_CPUTIME_ID */
        !           543: 
        !           544: #define start_timing(start) ((start)->tv_sec = 0, (start)->tv_nsec = 0)
        !           545: #define end_timing(...) (0)
        !           546: 
        !           547: #endif /* CLOCK_THREAD_CPUTIME_ID */
        !           548: 
1.1       misho     549: /**
                    550:  * Run a single test case with fixtures
                    551:  */
1.1.1.2 ! misho     552: static bool run_case(test_case_t *tcase, test_runner_init_t init, char *cfg,
        !           553:                                         level_t level)
1.1       misho     554: {
                    555:        enumerator_t *enumerator;
                    556:        test_function_t *tfun;
1.1.1.2 ! misho     557:        double *times;
        !           558:        double total_time = 0;
        !           559:        int tests = 0, ti = 0, passed = 0;
1.1       misho     560:        array_t *failures, *warnings;
                    561: 
1.1.1.2 ! misho     562:        /* determine the number of tests we will run */
        !           563:        enumerator = array_create_enumerator(tcase->functions);
        !           564:        while (enumerator->enumerate(enumerator, &tfun))
        !           565:        {
        !           566:                tests += tfun->end - tfun->start;
        !           567:        }
        !           568:        enumerator->destroy(enumerator);
        !           569:        times = calloc(tests, sizeof(double));
        !           570: 
1.1       misho     571:        failures = array_create(sizeof(failure_t), 0);
                    572:        warnings = array_create(sizeof(failure_t), 0);
                    573: 
                    574:        fprintf(stderr, "    Running case '%s': ", tcase->name);
                    575:        fflush(stderr);
                    576: 
                    577:        enumerator = array_create_enumerator(tcase->functions);
                    578:        while (enumerator->enumerate(enumerator, &tfun))
                    579:        {
                    580:                int i, rounds = 0;
                    581: 
                    582:                for (i = tfun->start; i < tfun->end; i++)
                    583:                {
                    584:                        if (pre_test(init, cfg))
                    585:                        {
1.1.1.2 ! misho     586:                                struct timespec start;
1.1       misho     587:                                bool ok = FALSE;
                    588:                                int leaks = 0;
                    589: 
1.1.1.2 ! misho     590:                                if (level >= 0)
        !           591:                                {
        !           592:                                        fprintf(stderr, "\nRunning function '%s' [%d]:\n",
        !           593:                                                        tfun->name, i);
        !           594:                                }
        !           595: 
1.1       misho     596:                                test_setup_timeout(tcase->timeout);
1.1.1.2 ! misho     597:                                start_timing(&start);
1.1       misho     598: 
1.1.1.2 ! misho     599:                                if (call_fixture(tcase, TRUE, i))
1.1       misho     600:                                {
                    601:                                        if (run_test(tfun, i))
                    602:                                        {
1.1.1.2 ! misho     603:                                                if (call_fixture(tcase, FALSE, i))
1.1       misho     604:                                                {
                    605:                                                        ok = TRUE;
                    606:                                                }
                    607:                                        }
                    608:                                        else
                    609:                                        {
1.1.1.2 ! misho     610:                                                call_fixture(tcase, FALSE, i);
1.1       misho     611:                                        }
                    612:                                }
                    613:                                if (!post_test(init, ok, failures, tfun->name, i, &leaks))
                    614:                                {
                    615:                                        ok = FALSE;
                    616:                                }
                    617: 
1.1.1.2 ! misho     618:                                times[ti] = end_timing(&start);
        !           619:                                total_time += times[ti++];
1.1       misho     620:                                test_setup_timeout(0);
                    621: 
                    622:                                if (ok)
                    623:                                {
                    624:                                        if (!leaks)
                    625:                                        {
                    626:                                                rounds++;
                    627:                                                if (!collect_warning_info(warnings, tfun->name, i))
                    628:                                                {
                    629:                                                        fprintf(stderr, "%s+%s", TTY(GREEN), TTY(DEF));
                    630:                                                }
                    631:                                                else
                    632:                                                {
                    633:                                                        fprintf(stderr, "%s~%s", TTY(YELLOW), TTY(DEF));
                    634:                                                }
                    635:                                        }
                    636:                                }
                    637:                                else
                    638:                                {
                    639:                                        collect_failure_info(failures, tfun->name, i);
                    640:                                }
                    641:                                if (!ok || leaks)
                    642:                                {
                    643:                                        fprintf(stderr, "%s-%s", TTY(RED), TTY(DEF));
                    644:                                }
                    645:                        }
                    646:                        else
                    647:                        {
                    648:                                fprintf(stderr, "!");
                    649:                        }
                    650:                }
                    651:                fflush(stderr);
                    652:                if (rounds == tfun->end - tfun->start)
                    653:                {
                    654:                        passed++;
                    655:                }
                    656:        }
                    657:        enumerator->destroy(enumerator);
                    658: 
1.1.1.2 ! misho     659:        if (total_time)
        !           660:        {
        !           661:                fprintf(stderr, " %s%s%.3f ms%s", tty_escape_get(2, TTY_BOLD),
        !           662:                                TTY(BLUE), total_time, tty_escape_get(2, TTY_RESET));
        !           663:                if (ti > 1)
        !           664:                {
        !           665:                        fprintf(stderr, " %s[", TTY(BLUE));
        !           666:                        for (ti = 0; ti < tests; ti++)
        !           667:                        {
        !           668:                                fprintf(stderr, "%s%.3f ms", times[ti], ti == 0 ? "" : ", ");
        !           669:                        }
        !           670:                        fprintf(stderr, "]%s", TTY(DEF));
        !           671:                }
        !           672:        }
1.1       misho     673:        fprintf(stderr, "\n");
                    674: 
                    675:        print_failures(warnings, TRUE);
                    676:        print_failures(failures, FALSE);
                    677:        array_destroy(failures);
                    678:        array_destroy(warnings);
                    679: 
                    680:        return passed == array_count(tcase->functions);
                    681: }
                    682: 
                    683: /**
                    684:  * Run a single test suite
                    685:  */
1.1.1.2 ! misho     686: static bool run_suite(test_suite_t *suite, test_runner_init_t init, char *cfg,
        !           687:                                          level_t level)
1.1       misho     688: {
                    689:        enumerator_t *enumerator;
                    690:        test_case_t *tcase;
                    691:        int passed = 0;
                    692: 
                    693:        fprintf(stderr, "  Running suite '%s':\n", suite->name);
                    694: 
                    695:        enumerator = array_create_enumerator(suite->tcases);
                    696:        while (enumerator->enumerate(enumerator, &tcase))
                    697:        {
1.1.1.2 ! misho     698:                if (run_case(tcase, init, cfg, level))
1.1       misho     699:                {
                    700:                        passed++;
                    701:                }
                    702:        }
                    703:        enumerator->destroy(enumerator);
                    704: 
                    705:        if (passed == array_count(suite->tcases))
                    706:        {
                    707:                fprintf(stderr, "  %sPassed all %u '%s' test cases%s\n",
                    708:                                TTY(GREEN), array_count(suite->tcases), suite->name, TTY(DEF));
                    709:                return TRUE;
                    710:        }
                    711:        fprintf(stderr, "  %sPassed %u/%u '%s' test cases%s\n",
                    712:                        TTY(RED), passed, array_count(suite->tcases), suite->name, TTY(DEF));
                    713:        return FALSE;
                    714: }
                    715: 
                    716: /**
                    717:  * See header.
                    718:  */
                    719: int test_runner_run(const char *name, test_configuration_t configs[],
                    720:                                        test_runner_init_t init)
                    721: {
                    722:        array_t *suites;
                    723:        test_suite_t *suite;
                    724:        enumerator_t *enumerator;
                    725:        int passed = 0, result;
                    726:        level_t level = LEVEL_SILENT;
                    727:        char *cfg, *runners, *verbosity;
                    728: 
                    729:        /* redirect all output to stderr (to redirect make's stdout to /dev/null) */
                    730:        dup2(2, 1);
                    731: 
                    732:        runners = getenv("TESTS_RUNNERS");
                    733:        if (runners && !is_in_filter(name, runners))
                    734:        {
                    735:                return EXIT_SUCCESS;
                    736:        }
                    737: 
                    738:        cfg = getenv("TESTS_STRONGSWAN_CONF");
                    739: 
                    740:        suites = load_suites(configs, init, cfg);
                    741:        if (!suites)
                    742:        {
                    743:                return EXIT_FAILURE;
                    744:        }
                    745: 
                    746:        verbosity = getenv("TESTS_VERBOSITY");
                    747:        if (verbosity)
                    748:        {
                    749:                level = atoi(verbosity);
                    750:        }
                    751:        dbg_default_set_level(level);
                    752: 
                    753:        fprintf(stderr, "Running %u '%s' test suites:\n", array_count(suites), name);
                    754: 
                    755:        enumerator = array_create_enumerator(suites);
                    756:        while (enumerator->enumerate(enumerator, &suite))
                    757:        {
1.1.1.2 ! misho     758:                if (run_suite(suite, init, cfg, level))
1.1       misho     759:                {
                    760:                        passed++;
                    761:                }
                    762:        }
                    763:        enumerator->destroy(enumerator);
                    764: 
                    765:        if (passed == array_count(suites))
                    766:        {
                    767:                fprintf(stderr, "%sPassed all %u '%s' suites%s\n",
                    768:                                TTY(GREEN), array_count(suites), name, TTY(DEF));
                    769:                result = EXIT_SUCCESS;
                    770:        }
                    771:        else
                    772:        {
                    773:                fprintf(stderr, "%sPassed %u of %u '%s' suites%s\n",
                    774:                                TTY(RED), passed, array_count(suites), name, TTY(DEF));
                    775:                result = EXIT_FAILURE;
                    776:        }
                    777: 
                    778:        unload_suites(suites);
                    779: 
                    780:        return result;
                    781: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>