File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / tests / test_runner.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:20:08 2021 UTC (3 years, 5 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, HEAD
strongswan 5.9.2

    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>
   31: #include <time.h>
   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: /**
   47:  * Destroy data associated with a test case.
   48:  */
   49: static void destroy_case(test_case_t *tcase)
   50: {
   51: 	array_destroy(tcase->functions);
   52: 	array_destroy(tcase->fixtures);
   53: }
   54: 
   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);
   61: 	free(suite);
   62: }
   63: 
   64: /**
   65:  * Identifies on which component to apply the given filter.
   66:  */
   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)
   77: {
   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;
   91: 	hashtable_t *listed;
   92: 	test_suite_t *suite;
   93: 	test_case_t *tcase;
   94: 	test_function_t *func;
   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: 	}
  103: 
  104: 	enumerator = array_create_enumerator(loaded);
  105: 	while (enumerator->enumerate(enumerator, &suite))
  106: 	{
  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))
  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: /**
  180:  * Removes and destroys test suites/cases/functions that are not selected or
  181:  * explicitly excluded. Takes names of two environment variables.
  182:  */
  183: static void filter_components(array_t *loaded, filter_component_t comp,
  184: 							  char *sel, char *exc)
  185: {
  186: 	char *filter;
  187: 
  188: 	filter = getenv(sel);
  189: 	if (filter)
  190: 	{
  191: 		apply_filter(loaded, comp, filter, FALSE);
  192: 	}
  193: 	filter = getenv(exc);
  194: 	if (filter)
  195: 	{
  196: 		apply_filter(loaded, comp, filter, TRUE);
  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: 	}
  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");
  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:  */
  288: static bool call_fixture(test_case_t *tcase, bool up, int i)
  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: 				{
  303: 					fixture->setup(i);
  304: 				}
  305: 			}
  306: 			else
  307: 			{
  308: 				if (fixture->teardown)
  309: 				{
  310: 					fixture->teardown(i);
  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: 
  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: 
  549: /**
  550:  * Run a single test case with fixtures
  551:  */
  552: static bool run_case(test_case_t *tcase, test_runner_init_t init, char *cfg,
  553: 					 level_t level)
  554: {
  555: 	enumerator_t *enumerator;
  556: 	test_function_t *tfun;
  557: 	double *times;
  558: 	double total_time = 0;
  559: 	int tests = 0, ti = 0, passed = 0;
  560: 	array_t *failures, *warnings;
  561: 
  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: 
  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: 			{
  586: 				struct timespec start;
  587: 				bool ok = FALSE;
  588: 				int leaks = 0;
  589: 
  590: 				if (level >= 0)
  591: 				{
  592: 					fprintf(stderr, "\nRunning function '%s' [%d]:\n",
  593: 							tfun->name, i);
  594: 				}
  595: 
  596: 				test_setup_timeout(tcase->timeout);
  597: 				start_timing(&start);
  598: 
  599: 				if (call_fixture(tcase, TRUE, i))
  600: 				{
  601: 					if (run_test(tfun, i))
  602: 					{
  603: 						if (call_fixture(tcase, FALSE, i))
  604: 						{
  605: 							ok = TRUE;
  606: 						}
  607: 					}
  608: 					else
  609: 					{
  610: 						call_fixture(tcase, FALSE, i);
  611: 					}
  612: 				}
  613: 				if (!post_test(init, ok, failures, tfun->name, i, &leaks))
  614: 				{
  615: 					ok = FALSE;
  616: 				}
  617: 
  618: 				times[ti] = end_timing(&start);
  619: 				total_time += times[ti++];
  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: 
  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: 	}
  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:  */
  686: static bool run_suite(test_suite_t *suite, test_runner_init_t init, char *cfg,
  687: 					  level_t level)
  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: 	{
  698: 		if (run_case(tcase, init, cfg, level))
  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: 	{
  758: 		if (run_suite(suite, init, cfg, level))
  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>