From 02a844cbf95b11d325a7bcf032944d179e60a6de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Tue, 3 Mar 2015 13:51:35 +0100 Subject: [PATCH] Add Ondrej Zajicek Unit Testing Framework - Add Ondrej Zajicek Unit Testing Framework -- BirdTest - An Integration the BirdTest (BT) into the BIRD's build system. --- birdtest/birdtest.c | 160 ++++++++++++++++++++++++++++++++++++++++++ birdtest/birdtest.h | 46 ++++++++++++ tools/Makefile-top.in | 2 +- tools/Makefile.in | 14 ++++ tools/Rules.in | 11 +++ 5 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 birdtest/birdtest.c create mode 100644 birdtest/birdtest.h diff --git a/birdtest/birdtest.c b/birdtest/birdtest.c new file mode 100644 index 00000000..cafadb2d --- /dev/null +++ b/birdtest/birdtest.c @@ -0,0 +1,160 @@ +/* + * BIRD Internet Routing Daemon -- BIRD Unit Testing Framework + * + * (c) 2015 Ondrej Zajicek + * (c) 2015 CZ.NIC z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "birdtest.h" + + +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; + + +void +bt_init(int argc, char *argv[]) +{ + int c; + + bt_filename = argv[0]; + + while ((c = getopt(argc, argv, "lcftv")) >= 0) + switch (c) + { + case 'l': + printf(" List of test cases:\n"); + list_tests = 1; + return; + + case 'c': + do_core = 1; + break; + + case 'f': + no_fork = 1; + break; + + case 't': + no_timeout = 1; + break; + + case 'v': + bt_verbose = 1; + 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: + printf("Usage: %s [-l] [-c] [-f] [-t] [-v] []\n", argv[0]); + exit(3); +} + +void +bt_test_case2(int (*test_fn)(void), const char *test_id, const char *dsc, int forked, int timeout) +{ + if (list_tests) + { + printf("%-12s - %s\n", test_id, dsc); + return; + } + + if (no_fork) + forked = 0; + + if (no_timeout) + timeout = 0; + + if (request && strcmp(test_id, request)) + return; + + int result = 0; + + bt_test_id = test_id; + + bt_note("Starting"); + + if (!forked) + { + alarm(timeout); + result = test_fn(); + } + else + { + pid_t pid = fork(); + bt_syscall(pid < 0, "fork"); + + if (pid == 0) + { + alarm(timeout); + result = test_fn(); + _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) + bt_log("Segmentation fault"); + else if (sn != SIGABRT) + bt_log("Signal %d received", sn); + } + + if (WCOREDUMP(s)) + bt_log("Core dumped"); + } + + if (result) + { + bt_log("Test case failed"); + exit(result); + } + + bt_note("Test case OK"); +} diff --git a/birdtest/birdtest.h b/birdtest/birdtest.h new file mode 100644 index 00000000..19a2d4f8 --- /dev/null +++ b/birdtest/birdtest.h @@ -0,0 +1,46 @@ +/* + * BIRD Internet Routing Daemon -- BIRD Unit Testing Framework + * + * (c) 2015 Ondrej Zajicek + * (c) 2015 CZ.NIC z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include +#include +#include +#include +#include + + +extern int bt_verbose; +extern const char *bt_filename; +extern const char *bt_test_id; + +void bt_init(int argc, char **argv); +void bt_test_case2(int (*fn)(void), const char *id, const char *dsc, int forked, int timeout); + +#define bt_test_case(fn,dsc,f,t) \ + bt_test_case2(fn, #fn, dsc, f, t) + +#define bt_log(format, ...) \ + fprintf(stderr, "%s: " format "\n", bt_filename, ##__VA_ARGS__) + +#define bt_note(format, ...) \ + do { if (bt_verbose) bt_log(format, ##__VA_ARGS__); } while (0) + +#define bt_abort() \ + bt_abort_msg("Aborted at %s:%d", __FILE__, __LINE__) + +#define bt_abort_msg(format, ...) \ + do { bt_log(format, ##__VA_ARGS__); abort(); } while (0) + +#define bt_assert(test) \ + bt_assert_msg(test, "Assertion (%s) failed at %s:%d", #test, __FILE__, __LINE__) + +#define bt_assert_msg(test,format, ...) \ + do { if (!(test)) bt_abort_msg(format, ##__VA_ARGS__); } while (0) + +#define bt_syscall(test,format, ...) \ + do { if (test) { bt_log(format ": %s", ##__VA_ARGS__, strerror(errno)); exit(3); } } while (0) diff --git a/tools/Makefile-top.in b/tools/Makefile-top.in index cf59f7a1..83ff4f58 100644 --- a/tools/Makefile-top.in +++ b/tools/Makefile-top.in @@ -3,7 +3,7 @@ objdir=@objdir@ -all depend tags install install-docs: +all depend tags install install-docs check: $(MAKE) -C $(objdir) $@ docs userdocs progdocs: diff --git a/tools/Makefile.in b/tools/Makefile.in index 062ba916..174b3e81 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -7,6 +7,20 @@ include Rules all: sysdep/paths.h .dep-stamp subdir daemon birdcl @CLIENT@ +check: build-tests + find . -name '*_test' -executable -exec {} \; + +build-tests: subdir birdtest/birdtest.a + set -e ; for a in $(dynamic-dirs) ; do $(MAKE) -C $$a build-test ; done + set -e ; for a in $(static-dirs) $(client-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile build-test ; done + +birdtest/birdtest.a: birdtest/birdtest.o + $(AR) rcs $@ $^ + +birdtest/birdtest.o: $(srcdir)/birdtest/birdtest.c + mkdir -p birdtest + $(CC) $(CFLAGS) -I$(srcdir)/birdtest $(TARGET_ARCH) -c $^ $(LDLIBS) -o $@ + daemon: $(exedir)/bird birdc: $(exedir)/birdc diff --git a/tools/Rules.in b/tools/Rules.in index ca930ec8..79bf0761 100644 --- a/tools/Rules.in +++ b/tools/Rules.in @@ -49,6 +49,17 @@ ifdef dir-name src-path := $(srcdir)/$(dir-name)/ endif +build-test: + for i in $(source); do \ + test_name=`echo $$i | sed 's/\.c$$/_test/g'` ; \ + test_source=$(src-path)$${test_name}.c ; \ + test_obj=$${test_name}.o ; \ + if [ -f $$test_source ]; then \ + $(CC) $(CFLAGS) -I $(srcdir)/birdtest/ -o $$test_obj -c $$test_source ; \ + $(CC) $(LDFLAGS) $$test_obj -o $$test_name $(root-rel)birdtest/birdtest.a ; \ + fi ; \ + done + all: cd $(root-rel) && make