Annotation of embedaddon/bird2/test/birdtest.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD -- Unit Test Framework (BIRD Test)
                      3:  *
                      4:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      5:  */
                      6: 
                      7: #include <inttypes.h>
                      8: #include <stdarg.h>
                      9: #include <stdint.h>
                     10: #include <stdio.h>
                     11: #include <stdlib.h>
                     12: #include <string.h>
                     13: #include <signal.h>
                     14: #include <time.h>
                     15: #include <unistd.h>
                     16: 
                     17: #include <sys/ioctl.h>
                     18: #include <sys/resource.h>
                     19: #include <sys/wait.h>
                     20: 
                     21: #include "test/birdtest.h"
                     22: #include "lib/string.h"
                     23: 
                     24: #ifdef HAVE_EXECINFO_H
                     25: #include <execinfo.h>
                     26: #endif
                     27: 
                     28: #define BACKTRACE_MAX_LINES 100
                     29: 
                     30: #define sprintf_concat(s, format, ...) \
                     31:     snprintf(s + strlen(s), sizeof(s) - strlen(s), format, ##__VA_ARGS__)
                     32: 
                     33: static const char *request;
                     34: static int list_tests;
                     35: static int do_core;
                     36: static int do_die;
                     37: static int no_fork;
                     38: static int no_timeout;
                     39: static int is_terminal;                /* Whether stdout is a live terminal or pipe redirect */
                     40: 
                     41: volatile sig_atomic_t async_config_flag;               /* Asynchronous reconfiguration/dump scheduled */
                     42: volatile sig_atomic_t async_dump_flag;
                     43: volatile sig_atomic_t async_shutdown_flag;
                     44: 
                     45: 
                     46: uint bt_verbose;
                     47: const char *bt_filename;
                     48: const char *bt_test_id;
                     49: 
                     50: int bt_result;                 /* Overall program run result */
                     51: int bt_suite_result;           /* One suit result */
                     52: char bt_out_fmt_buf[1024];     /* Temporary memory buffer for output of testing function */
                     53: 
                     54: struct timespec bt_begin, bt_suite_begin, bt_suite_case_begin;
                     55: 
                     56: u64 bt_random_state[] = {
                     57:   0x80241f302bd4d95d, 0xd10ba2e910f772b, 0xea188c9046f507c5, 0x4c4c581f04e6da05,
                     58:   0x53d9772877c1b647, 0xab8ce3eb466de6c5, 0xad02844c8a8e865f, 0xe8cc78080295065d
                     59: };
                     60: 
                     61: void
                     62: bt_init(int argc, char *argv[])
                     63: {
                     64:   int c;
                     65: 
                     66:   initstate(BT_RANDOM_SEED, (char *) bt_random_state, sizeof(bt_random_state));
                     67: 
                     68:   bt_verbose = 0;
                     69:   bt_filename = argv[0];
                     70:   bt_result = 1;
                     71:   bt_test_id = NULL;
                     72:   is_terminal = isatty(fileno(stdout));
                     73: 
                     74:   while ((c = getopt(argc, argv, "lcdftv")) >= 0)
                     75:     switch (c)
                     76:     {
                     77:       case 'l':
                     78:        list_tests = 1;
                     79:        break;
                     80: 
                     81:       case 'c':
                     82:        do_core = 1;
                     83:        break;
                     84: 
                     85:       case 'd':
                     86:        do_die = 1;
                     87:        break;
                     88: 
                     89:       case 'f':
                     90:        no_fork = 1;
                     91:        break;
                     92: 
                     93:       case 't':
                     94:        no_timeout = 1;
                     95:        break;
                     96: 
                     97:       case 'v':
                     98:        bt_verbose++;
                     99:        break;
                    100: 
                    101:       default:
                    102:        goto usage;
                    103:     }
                    104: 
                    105:   /* Optional requested test_id */
                    106:   if ((optind + 1) == argc)
                    107:     request = argv[optind++];
                    108: 
                    109:   if (optind != argc)
                    110:     goto usage;
                    111: 
                    112:   if (do_core)
                    113:   {
                    114:     struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
                    115:     int rv = setrlimit(RLIMIT_CORE, &rl);
                    116:     bt_syscall(rv < 0, "setrlimit RLIMIT_CORE");
                    117:   }
                    118: 
                    119:   clock_gettime(CLOCK_MONOTONIC, &bt_begin);
                    120: 
                    121:   return;
                    122: 
                    123:  usage:
                    124:   printf("Usage: %s [-l] [-c] [-d] [-f] [-t] [-vvv] [<test_suit_name>]\n", argv[0]);
                    125:   printf("Options: \n");
                    126:   printf("  -l   List all test suite names and descriptions \n");
                    127:   printf("  -c   Force unlimit core dumps (needs root privileges) \n");
                    128:   printf("  -d  Die on first failed test case \n");
                    129:   printf("  -f   No forking \n");
                    130:   printf("  -t   No timeout limit \n");
                    131:   printf("  -v   More verbosity, maximum is 3 -vvv \n");
                    132:   exit(3);
                    133: }
                    134: 
                    135: static void
                    136: bt_dump_backtrace(void)
                    137: {
                    138: #ifdef HAVE_EXECINFO_H
                    139:   void *buf[BACKTRACE_MAX_LINES];
                    140:   char **pp_backtrace;
                    141:   int lines, j;
                    142: 
                    143:   if (!bt_verbose)
                    144:     return;
                    145: 
                    146:   lines = backtrace(buf, BACKTRACE_MAX_LINES);
                    147:   bt_log("backtrace() returned %d addresses", lines);
                    148: 
                    149:   pp_backtrace = backtrace_symbols(buf, lines);
                    150:   if (pp_backtrace == NULL)
                    151:   {
                    152:     perror("backtrace_symbols");
                    153:     exit(EXIT_FAILURE);
                    154:   }
                    155: 
                    156:   for (j = 0; j < lines; j++)
                    157:     bt_log("%s", pp_backtrace[j]);
                    158: 
                    159:   free(pp_backtrace);
                    160: #endif /* HAVE_EXECINFO_H */
                    161: }
                    162: 
                    163: static
                    164: int bt_run_test_fn(int (*fn)(const void *), const void *fn_arg, int timeout)
                    165: {
                    166:   int result;
                    167:   alarm(timeout);
                    168: 
                    169:   result = fn(fn_arg);
                    170: 
                    171:   if (!bt_suite_result)
                    172:     result = 0;
                    173: 
                    174:   return result;
                    175: }
                    176: 
                    177: static uint
                    178: get_num_terminal_cols(void)
                    179: {
                    180:   struct winsize w = {};
                    181:   ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
                    182:   uint cols = w.ws_col;
                    183:   return (cols > 0 ? cols : 80);
                    184: }
                    185: 
                    186: /**
                    187:  * bt_log_result - pretty print of test result
                    188:  * @result: 1 or 0
                    189:  * @fmt: a description message (could be long, over more lines)
                    190:  * @argptr: variable argument list
                    191:  *
                    192:  * This function is used for pretty printing of test results on all verbose
                    193:  * levels.
                    194:  */
                    195: static void
                    196: bt_log_result(int result, u64 time, const char *fmt, va_list argptr)
                    197: {
                    198:   static char msg_buf[BT_BUFFER_SIZE];
                    199:   char *pos;
                    200: 
                    201:   snprintf(msg_buf, sizeof(msg_buf), "%s%s%s%s %" PRIu64 ".%09" PRIu64 "s",
                    202:           bt_filename,
                    203:           bt_test_id ? ": " : "",
                    204:           bt_test_id ? bt_test_id : "",
                    205:           (fmt && strlen(fmt) > 0) ? ": " : "",
                    206:           time / 1000000000,
                    207:           time % 1000000000
                    208:           );
                    209:   pos = msg_buf + strlen(msg_buf);
                    210: 
                    211:   if (fmt)
                    212:     vsnprintf(pos, sizeof(msg_buf) - (pos - msg_buf), fmt, argptr);
                    213: 
                    214:   int chrs = 0;
                    215:   for (uint i = 0; i < strlen(msg_buf); i += get_num_terminal_cols())
                    216:   {
                    217:     if (i)
                    218:       printf("\n");
                    219:     char *stop = msg_buf + i + get_num_terminal_cols();
                    220:     char backup = *stop;
                    221:     *stop = 0;
                    222:     chrs = printf("%s", msg_buf + i);
                    223:     *stop = backup;
                    224:   }
                    225: 
                    226:   int offset = get_num_terminal_cols() - chrs - BT_PROMPT_OK_FAIL_STRLEN;
                    227:   if (offset < 0)
                    228:   {
                    229:     printf("\n");
                    230:     offset = get_num_terminal_cols() - BT_PROMPT_OK_FAIL_STRLEN;
                    231:   }
                    232: 
                    233:   for (int i = 0; i < offset; i++)
                    234:     putchar(' ');
                    235: 
                    236:   const char *result_str = is_terminal ? BT_PROMPT_OK : BT_PROMPT_OK_NO_COLOR;
                    237:   if (!result)
                    238:     result_str = is_terminal ? BT_PROMPT_FAIL : BT_PROMPT_FAIL_NO_COLOR;
                    239: 
                    240:   printf("%s\n", result_str);
                    241: 
                    242:   if (do_die && !result)
                    243:     abort();
                    244: }
                    245: 
                    246: static u64
                    247: get_time_diff(struct timespec *begin)
                    248: {
                    249:   struct timespec end;
                    250:   clock_gettime(CLOCK_MONOTONIC, &end);
                    251:   return (end.tv_sec - begin->tv_sec) * 1000000000ULL
                    252:     + end.tv_nsec - begin->tv_nsec;
                    253: }
                    254: 
                    255: /**
                    256:  * bt_log_overall_result - pretty print of suite case result
                    257:  * @result: 1 or 0
                    258:  * @fmt: a description message (could be long, over more lines)
                    259:  * ...: variable argument list
                    260:  *
                    261:  * This function is used for pretty printing of test suite case result.
                    262:  */
                    263: static void
                    264: bt_log_overall_result(int result, const char *fmt, ...)
                    265: {
                    266:   va_list argptr;
                    267:   va_start(argptr, fmt);
                    268:   bt_log_result(result, get_time_diff(&bt_begin), fmt, argptr);
                    269:   va_end(argptr);
                    270: }
                    271: 
                    272: /**
                    273:  * bt_log_suite_result - pretty print of suite case result
                    274:  * @result: 1 or 0
                    275:  * @fmt: a description message (could be long, over more lines)
                    276:  * ...: variable argument list
                    277:  *
                    278:  * This function is used for pretty printing of test suite case result.
                    279:  */
                    280: void
                    281: bt_log_suite_result(int result, const char *fmt, ...)
                    282: {
                    283:   if (bt_verbose >= BT_VERBOSE_SUITE || !result)
                    284:   {
                    285:     va_list argptr;
                    286:     va_start(argptr, fmt);
                    287:     bt_log_result(result, get_time_diff(&bt_suite_begin), fmt, argptr);
                    288:     va_end(argptr);
                    289:   }
                    290: }
                    291: 
                    292: /**
                    293:  * bt_log_suite_case_result - pretty print of suite result
                    294:  * @result: 1 or 0
                    295:  * @fmt: a description message (could be long, over more lines)
                    296:  * ...: variable argument list
                    297:  *
                    298:  * This function is used for pretty printing of test suite result.
                    299:  */
                    300: void
                    301: bt_log_suite_case_result(int result, const char *fmt, ...)
                    302: {
                    303:   if(bt_verbose >= BT_VERBOSE_SUITE_CASE)
                    304:   {
                    305:     va_list argptr;
                    306:     va_start(argptr, fmt);
                    307:     bt_log_result(result, get_time_diff(&bt_suite_case_begin), fmt, argptr);
                    308:     va_end(argptr);
                    309:   }
                    310: }
                    311: 
                    312: int
                    313: bt_test_suite_base(int (*fn)(const void *), const char *id, const void *fn_arg, int forked, int timeout, const char *dsc, ...)
                    314: {
                    315:   if (list_tests)
                    316:   {
                    317:     printf("%28s - ", id);
                    318:     va_list args;
                    319:     va_start(args, dsc);
                    320:     vprintf(dsc, args);
                    321:     va_end(args);
                    322:     printf("\n");
                    323:     return 1;
                    324:   }
                    325: 
                    326:   if (no_fork)
                    327:     forked = 0;
                    328: 
                    329:   if (no_timeout)
                    330:     timeout = 0;
                    331: 
                    332:   if (request && strcmp(id, request))
                    333:     return 1;
                    334: 
                    335:   bt_suite_result = 1;
                    336:   bt_test_id = id;
                    337: 
                    338:   if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL)
                    339:     bt_log("Starting");
                    340: 
                    341:   clock_gettime(CLOCK_MONOTONIC, &bt_suite_begin);
                    342: 
                    343:   if (!forked)
                    344:   {
                    345:     bt_suite_result = bt_run_test_fn(fn, fn_arg, timeout);
                    346:   }
                    347:   else
                    348:   {
                    349:     pid_t pid = fork();
                    350:     bt_syscall(pid < 0, "fork");
                    351: 
                    352:     if (pid == 0)
                    353:     {
                    354:       /* child of fork */
                    355:       _exit(bt_run_test_fn(fn, fn_arg, timeout));
                    356:     }
                    357: 
                    358:     int s;
                    359:     int rv = waitpid(pid, &s, 0);
                    360:     bt_syscall(rv < 0, "waitpid");
                    361: 
                    362:     if (WIFEXITED(s))
                    363:     {
                    364:       /* Normal exit */
                    365:       bt_suite_result = WEXITSTATUS(s);
                    366:     }
                    367:     else if (WIFSIGNALED(s))
                    368:     {
                    369:       /* Stopped by signal */
                    370:       bt_suite_result = 0;
                    371: 
                    372:       int sn = WTERMSIG(s);
                    373:       if (sn == SIGALRM)
                    374:       {
                    375:        bt_log("Timeout expired");
                    376:       }
                    377:       else if (sn == SIGSEGV)
                    378:       {
                    379:        bt_log("Segmentation fault");
                    380:        bt_dump_backtrace();
                    381:       }
                    382:       else if (sn != SIGABRT)
                    383:        bt_log("Signal %d received", sn);
                    384:     }
                    385: 
                    386:     if (WCOREDUMP(s) && bt_verbose)
                    387:       bt_log("Core dumped");
                    388:   }
                    389: 
                    390:   if (!bt_suite_result)
                    391:     bt_result = 0;
                    392: 
                    393:   bt_log_suite_result(bt_suite_result, NULL);
                    394:   bt_test_id = NULL;
                    395: 
                    396:   return bt_suite_result;
                    397: }
                    398: 
                    399: int
                    400: bt_exit_value(void)
                    401: {
                    402:   if (!list_tests || (list_tests && !bt_result))
                    403:     bt_log_overall_result(bt_result, "");
                    404:   return bt_result ? EXIT_SUCCESS : EXIT_FAILURE;
                    405: }
                    406: 
                    407: /**
                    408:  * bt_assert_batch__ - test a batch of inputs/outputs tests
                    409:  * @opts: includes all necessary data
                    410:  *
                    411:  * Should be called using macro bt_assert_batch().
                    412:  * Returns 1 or 0.
                    413:  */
                    414: int
                    415: bt_assert_batch__(struct bt_batch *opts)
                    416: {
                    417:   int i;
                    418:   for (i = 0; i < opts->ndata; i++)
                    419:   {
                    420:     if (bt_verbose >= BT_VERBOSE_SUITE)
                    421:       clock_gettime(CLOCK_MONOTONIC, &bt_suite_case_begin);
                    422: 
                    423:     int bt_suit_case_result = opts->test_fn(opts->out_buf, opts->data[i].in, opts->data[i].out);
                    424: 
                    425:     if (bt_suit_case_result == 0)
                    426:       bt_suite_result = 0;
                    427: 
                    428:     char b[BT_BUFFER_SIZE];
                    429:     snprintf(b, sizeof(b), "%s(", opts->test_fn_name);
                    430: 
                    431:     opts->in_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].in);
                    432:     sprintf_concat(b, ") gives ");
                    433:     opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->out_buf);
                    434: 
                    435:     if (bt_suit_case_result == 0)
                    436:     {
                    437:       sprintf_concat(b, ", but expecting is ");
                    438:       opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].out);
                    439:     }
                    440: 
                    441:     bt_log_suite_case_result(bt_suit_case_result, "%s", b);
                    442:   }
                    443: 
                    444:   return bt_suite_result;
                    445: }
                    446: 
                    447: /**
                    448:  * bt_fmt_str - formating string into output buffer
                    449:  * @buf: buffer for write
                    450:  * @size: empty size in @buf
                    451:  * @data: null-byte terminated string
                    452:  *
                    453:  * This function can be used with bt_assert_batch() function.
                    454:  * Input @data should be const char * string.
                    455:  */
                    456: void
                    457: bt_fmt_str(char *buf, size_t size, const void *data)
                    458: {
                    459:   const byte *s = data;
                    460: 
                    461:   snprintf(buf, size, "\"");
                    462:   while (*s)
                    463:   {
                    464:     snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(*s) ? "%c" : "\\%03u", *s);
                    465:     s++;
                    466:   }
                    467:   snprintf(buf+strlen(buf), size-strlen(buf), "\"");
                    468: }
                    469: 
                    470: /**
                    471:  * bt_fmt_unsigned - formating unsigned int into output buffer
                    472:  * @buf: buffer for write
                    473:  * @size: empty size in @buf
                    474:  * @data: unsigned number
                    475:  *
                    476:  * This function can be used with bt_assert_batch() function.
                    477:  */
                    478: void
                    479: bt_fmt_unsigned(char *buf, size_t size, const void *data)
                    480: {
                    481:   const uint *n = data;
                    482:   snprintf(buf, size, "0x%x (%u)", *n, *n);
                    483: }
                    484: 
                    485: /**
                    486:  * bt_fmt_ipa - formating ip_addr into output buffer
                    487:  * @buf: buffer for write
                    488:  * @size: empty size in @buf
                    489:  * @data: should be struct ip_addr *
                    490:  *
                    491:  * This function can be used with bt_assert_batch() function.
                    492:  */
                    493: void
                    494: bt_fmt_ipa(char *buf, size_t size, const void *data)
                    495: {
                    496:   const ip_addr *ip = data;
                    497:   bsnprintf(buf, size, "%I", *ip);
                    498: }
                    499: 
                    500: int
                    501: bt_is_char(byte c)
                    502: {
                    503:   return (c >= (byte) 32 && c <= (byte) 126);
                    504: }
                    505: 
                    506: /*
                    507:  * Mock-ups of all necessary public functions in main.c
                    508:  */
                    509: 
                    510: char *bird_name;
                    511: void async_config(void) {}
                    512: void async_dump(void) {}
                    513: void async_shutdown(void) {}
                    514: void cmd_check_config(char *name UNUSED) {}
                    515: void cmd_reconfig(char *name UNUSED, int type UNUSED, int timeout UNUSED) {}
                    516: void cmd_reconfig_confirm(void) {}
                    517: void cmd_reconfig_undo(void) {}
                    518: void cmd_reconfig_status(void) {}
                    519: void cmd_graceful_restart(void) {}
                    520: void cmd_shutdown(void) {}
                    521: void cmd_reconfig_undo_notify(void) {}
                    522: 
                    523: #include "nest/bird.h"
                    524: #include "lib/net.h"
                    525: #include "conf/conf.h"
                    526: void sysdep_preconfig(struct config *c UNUSED) {}
                    527: int sysdep_commit(struct config *new UNUSED, struct config *old UNUSED) { return 0; }
                    528: void sysdep_shutdown_done(void) {}
                    529: 
                    530: #include "nest/cli.h"
                    531: int cli_get_command(cli *c UNUSED) { return 0; }
                    532: void cli_write_trigger(cli *c UNUSED) {}
                    533: cli *cmd_reconfig_stored_cli;

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