2015-03-03 12:51:35 +00:00
|
|
|
/*
|
2015-03-19 17:38:38 +00:00
|
|
|
* BIRD -- Unit Test Framework (BIRD Test)
|
2015-03-03 12:51:35 +00:00
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdint.h>
|
2015-03-03 12:51:35 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2015-03-23 16:40:13 +00:00
|
|
|
#include <signal.h>
|
2015-04-13 08:52:21 +00:00
|
|
|
#include <unistd.h>
|
2015-04-03 10:42:49 +00:00
|
|
|
#include <execinfo.h>
|
2015-03-03 12:51:35 +00:00
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
#include <sys/ioctl.h>
|
2015-03-03 12:51:35 +00:00
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
2015-03-23 16:40:13 +00:00
|
|
|
#include "test/birdtest.h"
|
2015-03-03 12:51:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
static const char *request;
|
|
|
|
static int list_tests;
|
|
|
|
static int do_core;
|
|
|
|
static int no_fork;
|
|
|
|
static int no_timeout;
|
|
|
|
|
|
|
|
int bt_verbose;
|
|
|
|
const char *bt_filename;
|
|
|
|
const char *bt_test_id;
|
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
int bt_success;
|
2015-04-15 09:51:24 +00:00
|
|
|
int bt_test_suite_success;
|
2015-04-13 08:52:21 +00:00
|
|
|
|
2015-04-03 10:44:47 +00:00
|
|
|
int
|
|
|
|
bt_rand_num(void)
|
|
|
|
{
|
|
|
|
/* Seeded in bt_init() */
|
|
|
|
return random();
|
|
|
|
}
|
|
|
|
|
2015-03-03 12:51:35 +00:00
|
|
|
void
|
|
|
|
bt_init(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
bt_success = 1;
|
2015-03-27 13:03:47 +00:00
|
|
|
srandom(BT_RANDOM_SEED);
|
|
|
|
|
2015-03-13 17:27:33 +00:00
|
|
|
bt_verbose = 0;
|
2015-03-03 12:51:35 +00:00
|
|
|
bt_filename = argv[0];
|
2015-04-13 08:52:21 +00:00
|
|
|
bt_test_id = NULL;
|
2015-03-03 12:51:35 +00:00
|
|
|
|
|
|
|
while ((c = getopt(argc, argv, "lcftv")) >= 0)
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 'l':
|
2015-03-13 17:29:21 +00:00
|
|
|
printf("\n"
|
|
|
|
" List of test cases \n"
|
|
|
|
"------------------------------\n");
|
2015-03-03 12:51:35 +00:00
|
|
|
list_tests = 1;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
do_core = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
no_fork = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 't':
|
|
|
|
no_timeout = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'v':
|
2015-03-13 17:27:33 +00:00
|
|
|
bt_verbose++;
|
2015-03-03 12:51:35 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Optional requested test_id */
|
|
|
|
if ((optind + 1) == argc)
|
|
|
|
request = argv[optind++];
|
|
|
|
|
|
|
|
if (optind != argc)
|
|
|
|
goto usage;
|
|
|
|
|
|
|
|
if (do_core)
|
|
|
|
{
|
|
|
|
struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
|
|
|
|
int rv = setrlimit(RLIMIT_CORE, &rl);
|
|
|
|
bt_syscall(rv < 0, "setrlimit RLIMIT_CORE");
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
usage:
|
2015-03-13 17:27:33 +00:00
|
|
|
printf("Usage: %s [-l] [-c] [-f] [-t] [-vv] [<test_id>]\n", argv[0]);
|
2015-03-03 12:51:35 +00:00
|
|
|
exit(3);
|
|
|
|
}
|
|
|
|
|
2015-04-03 10:42:49 +00:00
|
|
|
static void
|
|
|
|
dump_stack(void)
|
|
|
|
{
|
|
|
|
static void *backbuf[50];
|
|
|
|
int levels;
|
|
|
|
|
|
|
|
levels = backtrace(backbuf, 50);
|
|
|
|
backtrace_symbols_fd(backbuf, levels, STDERR_FILENO);
|
|
|
|
}
|
|
|
|
|
2015-03-03 12:51:35 +00:00
|
|
|
void
|
2015-04-13 08:42:10 +00:00
|
|
|
bt_test_suite5(int (*test_fn)(void), const char *test_id, const char *dsc, int forked, int timeout)
|
2015-03-03 12:51:35 +00:00
|
|
|
{
|
|
|
|
if (list_tests)
|
|
|
|
{
|
2015-03-13 17:29:21 +00:00
|
|
|
printf("%28s : %s\n", test_id, dsc);
|
2015-03-03 12:51:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (no_fork)
|
|
|
|
forked = 0;
|
|
|
|
|
|
|
|
if (no_timeout)
|
|
|
|
timeout = 0;
|
|
|
|
|
|
|
|
if (request && strcmp(test_id, request))
|
|
|
|
return;
|
|
|
|
|
|
|
|
int result = 0;
|
2015-04-15 09:51:24 +00:00
|
|
|
bt_test_suite_success = 1;
|
2015-03-03 12:51:35 +00:00
|
|
|
|
|
|
|
bt_test_id = test_id;
|
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
if (bt_verbose >= BT_VERBOSE_DEBUG)
|
|
|
|
bt_log("Starting");
|
2015-03-03 12:51:35 +00:00
|
|
|
|
|
|
|
if (!forked)
|
|
|
|
{
|
|
|
|
alarm(timeout);
|
|
|
|
result = test_fn();
|
2015-04-15 09:51:24 +00:00
|
|
|
result &= bt_test_suite_success;
|
2015-03-03 12:51:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pid_t pid = fork();
|
|
|
|
bt_syscall(pid < 0, "fork");
|
|
|
|
|
|
|
|
if (pid == 0)
|
|
|
|
{
|
|
|
|
alarm(timeout);
|
|
|
|
result = test_fn();
|
2015-04-15 09:51:24 +00:00
|
|
|
result &= bt_test_suite_success;
|
2015-03-03 12:51:35 +00:00
|
|
|
_exit(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
int s;
|
|
|
|
int rv = waitpid(pid, &s, 0);
|
|
|
|
bt_syscall(rv < 0, "waitpid");
|
|
|
|
|
|
|
|
result = 2;
|
|
|
|
if (WIFEXITED(s))
|
|
|
|
result = WEXITSTATUS(s);
|
|
|
|
else if (WIFSIGNALED(s))
|
|
|
|
{
|
|
|
|
int sn = WTERMSIG(s);
|
|
|
|
if (sn == SIGALRM)
|
|
|
|
bt_log("Timeout expired");
|
|
|
|
else if (sn == SIGSEGV)
|
2015-04-03 10:42:49 +00:00
|
|
|
{
|
|
|
|
bt_log("Segmentation fault:");
|
|
|
|
dump_stack();
|
|
|
|
}
|
2015-03-03 12:51:35 +00:00
|
|
|
else if (sn != SIGABRT)
|
|
|
|
bt_log("Signal %d received", sn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WCOREDUMP(s))
|
|
|
|
bt_log("Core dumped");
|
|
|
|
}
|
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
bt_success &= (result == BT_SUCCESS ? 1 : 0);
|
|
|
|
bt_result((result == BT_SUCCESS ? BT_PROMPT_OK : BT_PROMPT_FAIL), "%s", bt_test_id);
|
|
|
|
bt_test_id = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint
|
|
|
|
get_num_terminal_cols(void)
|
|
|
|
{
|
|
|
|
struct winsize w;
|
|
|
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
|
|
|
return w.ws_col;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bt_result(const char *to_right_align_msg, const char *to_left_align_msg, ...)
|
|
|
|
{
|
|
|
|
if (bt_verbose)
|
2015-03-03 12:51:35 +00:00
|
|
|
{
|
2015-04-13 08:52:21 +00:00
|
|
|
char msg_buf[BT_BUFFER_SIZE];
|
|
|
|
|
2015-04-15 09:51:24 +00:00
|
|
|
snprintf(msg_buf, sizeof(char)*BT_BUFFER_SIZE, "%s: ", bt_filename);
|
|
|
|
|
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, to_left_align_msg);
|
2015-04-13 08:52:21 +00:00
|
|
|
vsnprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf), to_left_align_msg, argptr);
|
|
|
|
|
|
|
|
char fmt_buf[BT_BUFFER_SIZE];
|
|
|
|
uint line_len = strlen(msg_buf) + BT_PROMPT_OK_FAIL_LEN;
|
|
|
|
uint left_offset = (line_len / get_num_terminal_cols() + 1) * get_num_terminal_cols() - BT_PROMPT_OK_FAIL_LEN;
|
|
|
|
snprintf(fmt_buf, sizeof(fmt_buf), "%%-%us%%s\n", left_offset);
|
2015-03-03 12:51:35 +00:00
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
fprintf(stderr, fmt_buf, msg_buf, to_right_align_msg);
|
|
|
|
}
|
2015-03-03 12:51:35 +00:00
|
|
|
}
|
2015-03-27 13:03:47 +00:00
|
|
|
|
2015-04-13 08:52:21 +00:00
|
|
|
int
|
|
|
|
bt_end(void)
|
|
|
|
{
|
|
|
|
return !bt_success;
|
|
|
|
}
|
2015-04-15 09:51:24 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
bt_strncat_(char *buf, size_t buf_size, const char *str, ...)
|
|
|
|
{
|
|
|
|
if (str != NULL)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, str);
|
|
|
|
vsnprintf(buf + strlen(buf), buf_size, str, argptr);
|
|
|
|
}
|
|
|
|
}
|