mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-09-07 22:15:19 +00:00
Unit Testing for BIRD
- Unit Testing Framework (BirdTest) - Integration of BirdTest into the BIRD build system - Tests for several BIRD modules Based on squashed Pavel Tvrdik's int-test branch, updated for current int-new branch.
This commit is contained in:
parent
8860e991f6
commit
9b0a0ba9e6
33
Makefile.in
33
Makefile.in
@ -22,7 +22,7 @@ INSTALL_DATA=@INSTALL_DATA@
|
||||
|
||||
client=$(addprefix $(exedir)/,@CLIENT@)
|
||||
daemon=$(exedir)/bird
|
||||
protocols = @protocols@
|
||||
protocols=@protocols@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
@ -49,24 +49,26 @@ else
|
||||
endif
|
||||
|
||||
# Meta rules
|
||||
cleangoals := clean distclean
|
||||
docgoals := docs userdocs progdocs
|
||||
.PHONY: all daemon cli $(cleangoals) $(docgoals) tags
|
||||
testgoals := check test tests tests_run
|
||||
cleangoals := clean distclean testsclean
|
||||
.PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags
|
||||
all: daemon cli
|
||||
|
||||
daemon: $(daemon)
|
||||
cli: $(client)
|
||||
|
||||
# Include directories
|
||||
dirs := client conf doc filter lib nest $(addprefix proto/,$(protocols)) @sysdep_dirs@
|
||||
dirs := client conf doc filter lib nest test $(addprefix proto/,$(protocols)) @sysdep_dirs@
|
||||
|
||||
conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h)
|
||||
cf-local = $(conf-y-targets): $(s)config.Y
|
||||
|
||||
src-o-files = $(patsubst %.c,$(o)%.o,$(src))
|
||||
tests-target-files = $(patsubst %.c,$(o)%,$(tests_src))
|
||||
|
||||
all-daemon = $(exedir)/bird: $(obj)
|
||||
all-client = $(exedir)/birdc $(exedir)/birdcl: $(obj)
|
||||
all-daemon = $(daemon): $(obj)
|
||||
all-client = $(client): $(obj)
|
||||
|
||||
s = $(dir $(lastword $(MAKEFILE_LIST)))
|
||||
ifeq ($(srcdir),.)
|
||||
@ -109,6 +111,22 @@ $(objdir)/sysdep/paths.h: Makefile
|
||||
echo >>$@ "#define PATH_CONTROL_SOCKET \"@CONTROL_SOCKET@\""
|
||||
if test -n "@iproutedir@" ; then echo >>$@ "#define PATH_IPROUTE_DIR \"@iproutedir@\"" ; fi
|
||||
|
||||
# Unit tests rules
|
||||
|
||||
tests_targets_ok = $(addsuffix .ok,$(tests_targets))
|
||||
|
||||
$(tests_targets): %: %.o $(tests_objs)
|
||||
$(E)echo LD $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
$(tests_targets_ok): %.ok: %
|
||||
$(Q)$* 2>/dev/null && touch $*.ok
|
||||
|
||||
test: testsclean check
|
||||
check: tests tests_run
|
||||
tests: $(tests_targets)
|
||||
tests_run: $(tests_targets_ok)
|
||||
|
||||
# Finally include the computed dependencies
|
||||
|
||||
ifneq ($(filter-out $(cleangoals),$(MAKECMDGOALS)),)
|
||||
@ -147,6 +165,9 @@ clean::
|
||||
rm -f $(addprefix $(exedir)/,bird birdc birdcl)
|
||||
find $(objdir) -name "*.[od]" -exec rm -f '{}' '+'
|
||||
|
||||
testsclean:
|
||||
rm -f $(tests_targets_ok)
|
||||
|
||||
ifeq ($(objdir),obj)
|
||||
distclean: clean
|
||||
rm -rf $(objdir)
|
||||
|
@ -3,6 +3,8 @@ obj := $(src-o-files)
|
||||
|
||||
$(all-daemon)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
||||
ifdef DEBUG
|
||||
BISON_DEBUG=-t
|
||||
#FLEX_DEBUG=-d
|
||||
|
@ -49,12 +49,10 @@
|
||||
#include "nest/route.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "nest/iface.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/string.h"
|
||||
#include "lib/event.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "conf/conf.h"
|
||||
#include "filter/filter.h"
|
||||
|
||||
|
||||
static jmp_buf conf_jmpbuf;
|
||||
|
||||
@ -85,7 +83,7 @@ int undo_available; /* Undo was not requested from last reconfiguration */
|
||||
* further use. Returns a pointer to the structure.
|
||||
*/
|
||||
struct config *
|
||||
config_alloc(const byte *name)
|
||||
config_alloc(const char *name)
|
||||
{
|
||||
pool *p = rp_new(&root_pool, "Config");
|
||||
linpool *l = lp_new(p, 4080);
|
||||
@ -96,6 +94,7 @@ config_alloc(const byte *name)
|
||||
char *ndup = lp_allocu(l, nlen);
|
||||
memcpy(ndup, name, nlen);
|
||||
|
||||
init_list(&c->tests);
|
||||
c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
|
||||
c->pool = p;
|
||||
c->mem = l;
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef _BIRD_CONF_H_
|
||||
#define _BIRD_CONF_H_
|
||||
|
||||
#include "sysdep/config.h"
|
||||
#include "lib/ip.h"
|
||||
#include "lib/resource.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
|
||||
@ -21,6 +23,7 @@ struct config {
|
||||
list protos; /* Configured protocol instances (struct proto_config) */
|
||||
list tables; /* Configured routing tables (struct rtable_config) */
|
||||
list logfiles; /* Configured log files (sysdep) */
|
||||
list tests; /* Configured unit tests */
|
||||
|
||||
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
|
||||
char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
|
||||
@ -60,7 +63,7 @@ struct config {
|
||||
extern struct config *config; /* Currently active configuration */
|
||||
extern struct config *new_config; /* Configuration being parsed */
|
||||
|
||||
struct config *config_alloc(const byte *name);
|
||||
struct config *config_alloc(const char *name);
|
||||
int config_parse(struct config *);
|
||||
int cli_parse(struct config *);
|
||||
void config_free(struct config *);
|
||||
@ -161,6 +164,7 @@ static inline int cf_symbol_is_constant(struct symbol *sym)
|
||||
|
||||
/* Parser */
|
||||
|
||||
extern char *cf_text;
|
||||
int cf_parse(void);
|
||||
|
||||
/* Sysdep hooks */
|
||||
|
@ -56,7 +56,7 @@ if test "$ac_test_CFLAGS" != set ; then
|
||||
bird_cflags_default=yes
|
||||
fi
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
if test -z "$GCC" ; then
|
||||
AC_MSG_ERROR([This program requires the GNU C Compiler.])
|
||||
fi
|
||||
@ -220,6 +220,9 @@ BIRD_CHECK_STRUCT_IP_MREQN
|
||||
|
||||
if test "$enable_debug" = yes ; then
|
||||
AC_DEFINE(DEBUGGING)
|
||||
AC_CHECK_HEADER(execinfo.h, [AC_SEARCH_LIBS([backtrace, backtrace_symbols], [c execinfo], [AC_DEFINE(HAVE_EXECINFO_H)])])
|
||||
LDFLAGS="$LDFLAGS -rdynamic"
|
||||
CFLAGS="$CFLAGS -O0 -ggdb -g3 -gdwarf-4"
|
||||
if test "$enable_memcheck" = yes ; then
|
||||
AC_CHECK_LIB(dmalloc, dmalloc_debug)
|
||||
if test $ac_cv_lib_dmalloc_dmalloc_debug != yes ; then
|
||||
|
@ -1253,7 +1253,7 @@ foot).
|
||||
<cf/!˜/ membership operators) can be used to modify or test
|
||||
eclists, with ECs instead of pairs as arguments.
|
||||
|
||||
<tag/lclist/
|
||||
<tag><label id="type-lclist">lclist/</tag>
|
||||
Lclist is a data type used for BGP large community lists. Like eclists,
|
||||
lclists are very similar to clists, but they are sets of LCs instead of
|
||||
pairs. The same operations (like <cf/add/, <cf/delete/ or <cf/˜/
|
||||
|
@ -2,3 +2,7 @@ src := filter.c f-util.c tree.c trie.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_src := tree_test.c filter_test.c trie_test.c
|
||||
tests_targets := $(tests_targets) $(tests-target-files)
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
@ -323,7 +323,71 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove all new lines and doubled whitespaces
|
||||
* and convert all tabulators to spaces
|
||||
* and return a copy of string
|
||||
*/
|
||||
char *
|
||||
assert_copy_expr(const char *start, size_t len)
|
||||
{
|
||||
/* XXX: Allocates maybe a little more memory than we really finally need */
|
||||
char *str = cfg_alloc(len + 1);
|
||||
|
||||
char *dst = str;
|
||||
const char *src = start - 1;
|
||||
const char *end = start + len;
|
||||
while (++src < end)
|
||||
{
|
||||
if (*src == '\n')
|
||||
continue;
|
||||
|
||||
/* Skip doubled whitespaces */
|
||||
if (src != start)
|
||||
{
|
||||
const char *prev = src - 1;
|
||||
if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*src == '\t')
|
||||
*dst = ' ';
|
||||
else
|
||||
*dst = *src;
|
||||
|
||||
dst++;
|
||||
}
|
||||
*dst = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* assert_done - create f_instruction of bt_assert
|
||||
* @expr: expression in bt_assert()
|
||||
* @start: pointer to first char of test expression
|
||||
* @end: pointer to the last char of test expression
|
||||
*/
|
||||
static struct f_inst *
|
||||
assert_done(struct f_inst *expr, const char *start, const char *end)
|
||||
{
|
||||
struct f_inst *i;
|
||||
i = f_new_inst();
|
||||
i->code = P('a','s');
|
||||
i->a1.p = expr;
|
||||
|
||||
if (end >= start)
|
||||
{
|
||||
i->a2.p = assert_copy_expr(start, end - start + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this is a break of lexer buffer */
|
||||
i->a2.p = "???";
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
CF_DECLS
|
||||
|
||||
@ -341,12 +405,13 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
ADD, DELETE, CONTAINS, RESET,
|
||||
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
|
||||
EMPTY,
|
||||
FILTER, WHERE, EVAL)
|
||||
FILTER, WHERE, EVAL,
|
||||
BT_ASSERT, BT_TEST_SUITE)
|
||||
|
||||
%nonassoc THEN
|
||||
%nonassoc ELSE
|
||||
|
||||
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
|
||||
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr bt_assert
|
||||
%type <f> filter filter_body where_filter
|
||||
%type <i> type break_command ec_kind
|
||||
%type <i32> cnum
|
||||
@ -356,6 +421,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
%type <px> fprefix
|
||||
%type <s> decls declsn one_decl function_params
|
||||
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
|
||||
%type <t> get_cf_position
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
@ -375,6 +441,21 @@ filter_eval:
|
||||
EVAL term { f_eval_int($2); }
|
||||
;
|
||||
|
||||
CF_ADDTO(conf, bt_test_suite)
|
||||
bt_test_suite:
|
||||
BT_TEST_SUITE '(' SYM ',' text ')' {
|
||||
if (!($3->class & SYM_FUNCTION))
|
||||
cf_error("Function expected");
|
||||
|
||||
struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
|
||||
t->fn = $3->def;
|
||||
t->fn_name = $3->name;
|
||||
t->dsc = $5;
|
||||
|
||||
add_tail(&new_config->tests, &t->n);
|
||||
}
|
||||
;
|
||||
|
||||
type:
|
||||
INT { $$ = T_INT; }
|
||||
| BOOL { $$ = T_BOOL; }
|
||||
@ -835,6 +916,8 @@ term:
|
||||
| ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
|
||||
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
|
||||
|
||||
| bt_assert { $$ = $1; }
|
||||
|
||||
/* | term '.' LEN { $$->code = P('P','l'); } */
|
||||
|
||||
/* function_call is inlined here */
|
||||
@ -966,6 +1049,7 @@ cmd:
|
||||
$$->a1.p = $2;
|
||||
$$->a2.p = build_tree( $4 );
|
||||
}
|
||||
| bt_assert ';' { $$ = $1; }
|
||||
|
||||
|
||||
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
|
||||
@ -975,4 +1059,14 @@ cmd:
|
||||
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
|
||||
;
|
||||
|
||||
bt_assert:
|
||||
BT_ASSERT '(' get_cf_position term get_cf_position ')' { $$ = assert_done($4, $3 + 1, $5 - 1); }
|
||||
;
|
||||
|
||||
get_cf_position:
|
||||
{
|
||||
$$ = cf_text;
|
||||
};
|
||||
|
||||
|
||||
CF_END
|
||||
|
@ -52,6 +52,8 @@
|
||||
|
||||
#define CMP_ERROR 999
|
||||
|
||||
void (*bt_assert_hook)(int result, struct f_inst *assert);
|
||||
|
||||
static struct adata *
|
||||
adata_empty(struct linpool *pool, int l)
|
||||
{
|
||||
@ -563,8 +565,8 @@ f_rta_cow(void)
|
||||
|
||||
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
||||
|
||||
#define runtime(x) do { \
|
||||
log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \
|
||||
#define runtime(fmt, ...) do { \
|
||||
log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
|
||||
res.type = T_RETURN; \
|
||||
res.val.i = F_ERROR; \
|
||||
return res; \
|
||||
@ -1475,6 +1477,17 @@ interpret(struct f_inst *what)
|
||||
|
||||
break;
|
||||
|
||||
case P('a', 's'): /* Birdtest Assert */
|
||||
ONEARG;
|
||||
|
||||
if (v1.type != T_BOOL)
|
||||
runtime("Should be boolean value");
|
||||
|
||||
res.type = v1.type;
|
||||
res.val = v1.val;
|
||||
|
||||
CALL(bt_assert_hook, res.val.i, what);
|
||||
break;
|
||||
|
||||
default:
|
||||
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
|
||||
|
@ -16,16 +16,16 @@
|
||||
|
||||
struct f_inst { /* Instruction */
|
||||
struct f_inst *next; /* Structure is 16 bytes, anyway */
|
||||
u16 code;
|
||||
u16 aux;
|
||||
u16 code; /* Instruction code, see the interpret() function and P() macro */
|
||||
u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
|
||||
union {
|
||||
int i;
|
||||
void *p;
|
||||
} a1;
|
||||
} a1; /* The first argument */
|
||||
union {
|
||||
int i;
|
||||
void *p;
|
||||
} a2;
|
||||
} a2; /* The second argument */
|
||||
int lineno;
|
||||
};
|
||||
|
||||
@ -55,7 +55,7 @@ struct f_prefix {
|
||||
};
|
||||
|
||||
struct f_val {
|
||||
int type;
|
||||
int type; /* T_* */
|
||||
union {
|
||||
uint i;
|
||||
u64 ec;
|
||||
@ -205,4 +205,15 @@ struct f_trie
|
||||
|
||||
#define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */
|
||||
|
||||
/* Bird Tests */
|
||||
struct f_bt_test_suite {
|
||||
node n; /* Node in config->tests */
|
||||
struct f_inst *fn; /* Root of function */
|
||||
const char *fn_name; /* Name of test */
|
||||
const char *dsc; /* Description */
|
||||
};
|
||||
|
||||
/* Hook for call bt_assert() function in configuration */
|
||||
extern void (*bt_assert_hook)(int result, struct f_inst *assert);
|
||||
|
||||
#endif
|
||||
|
87
filter/filter_test.c
Normal file
87
filter/filter_test.c
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Filters: Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h"
|
||||
|
||||
#include "filter/filter.h"
|
||||
#include "conf/conf.h"
|
||||
|
||||
#define BT_CONFIG_FILE "filter/test.conf"
|
||||
|
||||
|
||||
static struct config *
|
||||
parse_config_file(const void *filename_void)
|
||||
{
|
||||
bt_bird_init();
|
||||
|
||||
size_t fn_size = strlen((const char *) filename_void) + 1;
|
||||
char *filename = alloca(fn_size);
|
||||
strncpy(filename, filename_void, fn_size);
|
||||
|
||||
struct config *c = bt_config_file_parse(filename);
|
||||
bt_bird_cleanup();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int
|
||||
run_function(const void *parsed_fn_def)
|
||||
{
|
||||
/* XXX: const -> non-const */
|
||||
struct f_inst *f = (struct f_inst *) parsed_fn_def;
|
||||
|
||||
linpool *tmp = lp_new(&root_pool, 4096);
|
||||
struct f_val res = f_eval(f, tmp);
|
||||
rfree(tmp);
|
||||
|
||||
if (res.type == T_RETURN && res.val.i >= F_REJECT)
|
||||
return BT_FAILURE;
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
bt_assert_filter(int result, struct f_inst *assert)
|
||||
{
|
||||
int bt_suit_case_result = BT_SUCCESS;
|
||||
if (!result)
|
||||
{
|
||||
bt_result = BT_FAILURE;
|
||||
bt_suite_result = BT_FAILURE;
|
||||
bt_suit_case_result = BT_FAILURE;
|
||||
}
|
||||
|
||||
bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, (char *) assert->a2.p);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
struct config *c = parse_config_file(BT_CONFIG_FILE);
|
||||
|
||||
if (c)
|
||||
{
|
||||
bt_assert_hook = bt_assert_filter;
|
||||
|
||||
struct f_bt_test_suite *t;
|
||||
WALK_LIST(t, c->tests)
|
||||
bt_test_suite_base(run_function, t->fn_name, t->fn, BT_FORKING, BT_TIMEOUT, "%s", t->dsc);
|
||||
}
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
1321
filter/test.conf
1321
filter/test.conf
File diff suppressed because it is too large
Load Diff
@ -2,4 +2,5 @@
|
||||
print "Entering include";
|
||||
print "Should be 2: ", 1+1;
|
||||
print "Leaving include";
|
||||
i = 42;
|
||||
|
||||
|
@ -18,6 +18,7 @@ protocol direct {
|
||||
|
||||
protocol kernel {
|
||||
disabled;
|
||||
ipv4; # Must be specified at least one channel
|
||||
# learn; # Learn all routes from the kernel
|
||||
# scan time 10; # Scan kernel tables every 10 seconds
|
||||
}
|
||||
@ -25,51 +26,58 @@ protocol kernel {
|
||||
protocol static {
|
||||
# disabled;
|
||||
|
||||
import filter { print "ahoj";
|
||||
print source;
|
||||
if source = RTS_STATIC then {
|
||||
print "It is from static";
|
||||
}
|
||||
print from;
|
||||
from = 1.2.3.4;
|
||||
print from;
|
||||
print scope;
|
||||
scope = SCOPE_HOST;
|
||||
print scope;
|
||||
if !(scope ~ [ SCOPE_HOST, SCOPE_SITE ]) then {
|
||||
print "Failed in test";
|
||||
quitbird;
|
||||
}
|
||||
|
||||
preference = 15;
|
||||
print preference;
|
||||
preference = 29;
|
||||
print preference;
|
||||
rip_metric = 1;
|
||||
print rip_metric;
|
||||
rip_metric = rip_metric + 5;
|
||||
print rip_metric;
|
||||
bgp_community = - empty - ;
|
||||
print "nazdar";
|
||||
bgp_community = add(bgp_community, (1,2));
|
||||
print "cau";
|
||||
bgp_community = add(bgp_community, (2,3));
|
||||
bgp_community.add((4,5));
|
||||
print "community = ", bgp_community;
|
||||
bgp_community.delete((2,3));
|
||||
print "community = ", bgp_community;
|
||||
bgp_community.empty;
|
||||
print "community = ", bgp_community;
|
||||
print "done";
|
||||
};
|
||||
ipv4 {
|
||||
export all;
|
||||
|
||||
import filter {
|
||||
print "ahoj";
|
||||
print source;
|
||||
if source = RTS_STATIC then {
|
||||
print "It is from static";
|
||||
}
|
||||
print from;
|
||||
from = 1.2.3.4;
|
||||
print from;
|
||||
print scope;
|
||||
scope = SCOPE_HOST;
|
||||
print scope;
|
||||
if !(scope ~ [ SCOPE_HOST, SCOPE_SITE ]) then {
|
||||
print "Failed in test";
|
||||
quitbird;
|
||||
}
|
||||
|
||||
preference = 15;
|
||||
print preference;
|
||||
preference = 29;
|
||||
print preference;
|
||||
rip_metric = 1;
|
||||
print rip_metric;
|
||||
rip_metric = rip_metric + 5;
|
||||
print rip_metric;
|
||||
|
||||
#
|
||||
# TODO: uncomment this part after finishing BGP integration version
|
||||
#
|
||||
# bgp_community = -empty-;
|
||||
# print "hi";
|
||||
# bgp_community = add(bgp_community, (1,2));
|
||||
# print "hello";
|
||||
# bgp_community = add(bgp_community, (2,3));
|
||||
# bgp_community.add((4,5));
|
||||
# print "community = ", bgp_community;
|
||||
# bgp_community.delete((2,3));
|
||||
# print "community = ", bgp_community;
|
||||
# bgp_community.empty;
|
||||
# print "community = ", bgp_community;
|
||||
# print "done";
|
||||
};
|
||||
};
|
||||
route 0.0.0.0/0 via 195.113.31.113;
|
||||
route 62.168.0.0/25 reject;
|
||||
route 1.2.3.4/32 via 195.113.31.124;
|
||||
# route 10.0.0.0/8 reject;
|
||||
# route 10.1.1.0:255.255.255.0 via 62.168.0.3;
|
||||
# route 10.1.2.0:255.255.255.0 via 62.168.0.3;
|
||||
# route 10.1.3.0:255.255.255.0 via 62.168.0.4;
|
||||
# route 10.2.0.0/24 via "arc0";
|
||||
export all;
|
||||
route 10.0.0.0/8 reject;
|
||||
route 10.1.1.0:255.255.255.0 via 62.168.0.3;
|
||||
route 10.1.2.0:255.255.255.0 via 62.168.0.3;
|
||||
route 10.1.3.0:255.255.255.0 via 62.168.0.4;
|
||||
route 10.2.0.0/24 via "arc0";
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ router id 62.168.0.1;
|
||||
|
||||
define xyzzy = (120+10);
|
||||
|
||||
protocol device {}
|
||||
|
||||
function callme(int arg1; int arg2)
|
||||
int local1;
|
||||
int local2;
|
||||
@ -30,7 +32,7 @@ function fifteen()
|
||||
return 15;
|
||||
}
|
||||
|
||||
function paths()
|
||||
function _paths()
|
||||
bgpmask pm1;
|
||||
bgpmask pm2;
|
||||
bgppath p2;
|
||||
@ -97,7 +99,7 @@ ip p;
|
||||
pair pp;
|
||||
int set is;
|
||||
prefix set pxs;
|
||||
string s;
|
||||
string str;
|
||||
{
|
||||
print "Testing filter language:";
|
||||
i = four;
|
||||
@ -129,8 +131,8 @@ string s;
|
||||
print "Testing pairs: (1,2) = ", (1,2), " = ", pp;
|
||||
print "Testing enums: ", RTS_DUMMY, " ", RTS_STATIC;
|
||||
|
||||
s = "Hello";
|
||||
print "Testing string: ", s, " true: ", s ~ "Hell*", " false: ", s ~ "ell*";
|
||||
str = "Hello";
|
||||
print "Testing string: ", str, " true: ", str ~ "Hell*", " false: ", str ~ "ell*";
|
||||
|
||||
b = true;
|
||||
print "Testing bool: ", b, ", ", !b;
|
||||
@ -156,11 +158,12 @@ string s;
|
||||
i = fifteen();
|
||||
print "Testing function calls: 15 = ", i;
|
||||
|
||||
paths();
|
||||
_paths();
|
||||
|
||||
print "done";
|
||||
quitbird;
|
||||
# print "*** FAIL: this is unreachable";
|
||||
return 0;
|
||||
print "*** FAIL: this is unreachable";
|
||||
quitbird; # quit with err exit code 1
|
||||
}
|
||||
|
||||
filter testf
|
||||
|
113
filter/test_bgp_filtering.conf
Normal file
113
filter/test_bgp_filtering.conf
Normal file
@ -0,0 +1,113 @@
|
||||
router id 62.168.0.1;
|
||||
|
||||
function net_martian()
|
||||
{
|
||||
return net ~ [ 169.254.0.0/16+, 172.16.0.0/12+, 192.168.0.0/16+, 10.0.0.0/8+,
|
||||
127.0.0.0/8+, 224.0.0.0/4+, 240.0.0.0/4+, 0.0.0.0/32-, 0.0.0.0/0{25,32}, 0.0.0.0/0{0,7} ];
|
||||
}
|
||||
|
||||
function net_local()
|
||||
{
|
||||
return net ~ [ 12.10.0.0/16+, 34.10.0.0/16+ ];
|
||||
}
|
||||
|
||||
function rt_import(int asn; int set peer_asns; prefix set peer_nets)
|
||||
{
|
||||
if ! (net ~ peer_nets) then return false;
|
||||
if ! (bgp_path.last ~ peer_asns) then return false;
|
||||
if bgp_path.first != asn then return false;
|
||||
if bgp_path.len > 64 then return false;
|
||||
if bgp_next_hop != from then return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function rt_import_all(int asn)
|
||||
{
|
||||
if net_martian() || net_local() then return false;
|
||||
if bgp_path.first != asn then return false;
|
||||
if bgp_path.len > 64 then return false;
|
||||
if bgp_next_hop != from then return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function rt_import_rs(int asn)
|
||||
{
|
||||
if net_martian() || net_local() then return false;
|
||||
if bgp_path.len > 64 then return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function rt_export()
|
||||
{
|
||||
if proto = "static_bgp" then return true;
|
||||
if source != RTS_BGP then return false;
|
||||
if net_martian() then return false;
|
||||
if bgp_path.len > 64 then return false;
|
||||
# return bgp_next_hop ~ [ 100.1.1.1, 100.1.1.2, 200.1.1.1 ];
|
||||
return bgp_path.first ~ [ 345, 346 ];
|
||||
}
|
||||
|
||||
|
||||
function rt_export_all()
|
||||
{
|
||||
if proto = "static_bgp" then return true;
|
||||
if source != RTS_BGP then return false;
|
||||
if net_martian() then return false;
|
||||
if bgp_path.len > 64 then return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
filter bgp_in_uplink_123
|
||||
{
|
||||
if ! rt_import_all(123) then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
filter bgp_out_uplink_123
|
||||
{
|
||||
if ! rt_export() then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
|
||||
filter bgp_in_peer_234
|
||||
{
|
||||
if ! rt_import(234, [ 234, 1234, 2345, 3456 ],
|
||||
[ 12.34.0.0/16, 23.34.0.0/16, 34.56.0.0/16 ])
|
||||
then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
filter bgp_out_peer_234
|
||||
{
|
||||
if ! rt_export() then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
filter bgp_in_rs
|
||||
{
|
||||
if ! rt_import_rs(bgp_path.last) then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
filter bgp_out_rs
|
||||
{
|
||||
if ! rt_export() then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
|
||||
filter bgp_in_client_345
|
||||
{
|
||||
if ! rt_import(345, [ 345 ], [ 34.5.0.0/16 ]) then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
filter bgp_out_client_345
|
||||
{
|
||||
if ! rt_export_all() then reject;
|
||||
accept;
|
||||
}
|
||||
|
||||
|
||||
|
304
filter/tree_test.c
Normal file
304
filter/tree_test.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Filters: Utility Functions Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h"
|
||||
|
||||
#include "filter/filter.h"
|
||||
#include "conf/conf.h"
|
||||
|
||||
#define MAX_TREE_HEIGHT 13
|
||||
|
||||
static void
|
||||
start_conf_env(void)
|
||||
{
|
||||
bt_bird_init();
|
||||
|
||||
pool *p = rp_new(&root_pool, "helper_pool");
|
||||
linpool *l = lp_new(p, 4080);
|
||||
cfg_mem = l;
|
||||
}
|
||||
|
||||
static struct f_tree *
|
||||
new_tree(uint id)
|
||||
{
|
||||
struct f_tree *tree = f_new_tree();
|
||||
tree->from.type = tree->to.type = T_INT;
|
||||
tree->from.val.i = tree->to.val.i = id;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/*
|
||||
* Show subtree in infix notation
|
||||
*/
|
||||
static void
|
||||
show_subtree(struct f_tree *node)
|
||||
{
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
show_subtree(node->left);
|
||||
|
||||
if (node->from.val.i == node->to.val.i)
|
||||
bt_debug("%u ", node->from.val.i);
|
||||
else
|
||||
bt_debug("%u..%u ", node->from.val.i, node->to.val.i);
|
||||
|
||||
show_subtree(node->right);
|
||||
}
|
||||
|
||||
static void
|
||||
show_tree2(struct f_tree *root_node, const char *tree_name)
|
||||
{
|
||||
bt_debug("%s: \n", tree_name);
|
||||
bt_debug("[ ");
|
||||
show_subtree(root_node);
|
||||
bt_debug("]\n\n");
|
||||
}
|
||||
|
||||
#define show_tree(tree) show_tree2(tree, #tree);
|
||||
|
||||
static uint
|
||||
get_nodes_count_full_bin_tree(uint height)
|
||||
{
|
||||
return (bt_naive_pow(2, height+1) - 1);
|
||||
}
|
||||
|
||||
static struct f_tree *
|
||||
get_balanced_full_subtree(uint height, uint idx)
|
||||
{
|
||||
struct f_tree *node = new_tree(idx);
|
||||
if (height > 0)
|
||||
{
|
||||
uint nodes_in_subtree = get_nodes_count_full_bin_tree(--height);
|
||||
node->left = get_balanced_full_subtree(height, idx - nodes_in_subtree/2 - 1);
|
||||
node->right = get_balanced_full_subtree(height, idx + nodes_in_subtree/2 + 1);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static struct f_tree *
|
||||
get_balanced_full_tree(uint height)
|
||||
{
|
||||
return get_balanced_full_subtree(height, get_nodes_count_full_bin_tree(height)/2);
|
||||
}
|
||||
|
||||
static struct f_tree *
|
||||
get_degenerated_left_tree(uint nodes_count)
|
||||
{
|
||||
struct f_tree *old = NULL;
|
||||
struct f_tree *new = NULL;
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < nodes_count; i++)
|
||||
{
|
||||
old = new;
|
||||
new = new_tree(nodes_count-1-i);
|
||||
new->left = old;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct f_tree *
|
||||
get_random_degenerated_left_tree(uint nodes_count)
|
||||
{
|
||||
struct f_tree *tree = get_degenerated_left_tree(nodes_count);
|
||||
|
||||
size_t avaible_indexes_size = nodes_count * sizeof(byte);
|
||||
byte *avaible_indexes = malloc(avaible_indexes_size);
|
||||
memset(avaible_indexes, 0, avaible_indexes_size);
|
||||
|
||||
struct f_tree *n;
|
||||
for (n = tree; n; n = n->left)
|
||||
{
|
||||
uint selected_idx;
|
||||
do
|
||||
{
|
||||
selected_idx = bt_random() % nodes_count;
|
||||
} while(avaible_indexes[selected_idx] != 0);
|
||||
|
||||
avaible_indexes[selected_idx] = 1;
|
||||
n->from.type = n->to.type = T_INT;
|
||||
n->from.val.i = n->to.val.i = selected_idx;
|
||||
}
|
||||
|
||||
free(avaible_indexes);
|
||||
return tree;
|
||||
}
|
||||
|
||||
static struct f_tree *
|
||||
get_balanced_tree_with_ranged_values(uint nodes_count)
|
||||
{
|
||||
struct f_tree *tree = get_degenerated_left_tree(nodes_count);
|
||||
|
||||
uint idx = 0;
|
||||
struct f_tree *n;
|
||||
for (n = tree; n; n = n->left)
|
||||
{
|
||||
n->from.type = n->to.type = T_INT;
|
||||
n->from.val.i = idx;
|
||||
idx += (uint)bt_random() / nodes_count; /* (... / nodes_count) preventing overflow an uint idx */
|
||||
n->to.val.i = idx++;
|
||||
}
|
||||
|
||||
return build_tree(tree);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
t_balancing(void)
|
||||
{
|
||||
start_conf_env();
|
||||
|
||||
uint height;
|
||||
for (height = 1; height < MAX_TREE_HEIGHT; height++)
|
||||
{
|
||||
uint nodes_count = get_nodes_count_full_bin_tree(height);
|
||||
|
||||
struct f_tree *simple_degenerated_tree = get_degenerated_left_tree(nodes_count);
|
||||
show_tree(simple_degenerated_tree);
|
||||
|
||||
struct f_tree *expected_balanced_tree = get_balanced_full_tree(height);
|
||||
show_tree(expected_balanced_tree);
|
||||
|
||||
struct f_tree *balanced_tree_from_simple = build_tree(simple_degenerated_tree);
|
||||
show_tree(balanced_tree_from_simple);
|
||||
|
||||
bt_assert(same_tree(balanced_tree_from_simple, expected_balanced_tree));
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
t_balancing_random(void)
|
||||
{
|
||||
start_conf_env();
|
||||
|
||||
uint height;
|
||||
for (height = 1; height < MAX_TREE_HEIGHT; height++)
|
||||
{
|
||||
uint nodes_count = get_nodes_count_full_bin_tree(height);
|
||||
|
||||
struct f_tree *expected_balanced_tree = get_balanced_full_tree(height);
|
||||
|
||||
uint i;
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
struct f_tree *random_degenerated_tree = get_random_degenerated_left_tree(nodes_count);
|
||||
show_tree(random_degenerated_tree);
|
||||
|
||||
struct f_tree *balanced_tree_from_random = build_tree(random_degenerated_tree);
|
||||
|
||||
show_tree(expected_balanced_tree);
|
||||
show_tree(balanced_tree_from_random);
|
||||
|
||||
bt_assert(same_tree(balanced_tree_from_random, expected_balanced_tree));
|
||||
}
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_find(void)
|
||||
{
|
||||
start_conf_env();
|
||||
|
||||
uint height;
|
||||
for (height = 1; height < MAX_TREE_HEIGHT; height++)
|
||||
{
|
||||
uint nodes_count = get_nodes_count_full_bin_tree(height);
|
||||
|
||||
struct f_tree *tree = get_balanced_full_tree(height);
|
||||
show_tree(tree);
|
||||
|
||||
struct f_val looking_up_value = {
|
||||
.type = T_INT
|
||||
};
|
||||
for(looking_up_value.val.i = 0; looking_up_value.val.i < nodes_count; looking_up_value.val.i++)
|
||||
{
|
||||
struct f_tree *found_tree = find_tree(tree, looking_up_value);
|
||||
bt_assert((val_compare(looking_up_value, found_tree->from) == 0) && (val_compare(looking_up_value, found_tree->to) == 0));
|
||||
}
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static uint
|
||||
get_max_value_in_unbalanced_tree(struct f_tree *node, uint max)
|
||||
{
|
||||
if (!node)
|
||||
return max;
|
||||
|
||||
if (node->to.val.i > max)
|
||||
max = node->to.val.i;
|
||||
|
||||
uint max_left = get_max_value_in_unbalanced_tree(node->left, max);
|
||||
if (max_left > max)
|
||||
max = max_left;
|
||||
|
||||
uint max_right = get_max_value_in_unbalanced_tree(node->right, max);
|
||||
if (max_right > max)
|
||||
max = max_right;
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
static int
|
||||
t_find_ranges(void)
|
||||
{
|
||||
start_conf_env();
|
||||
|
||||
uint height;
|
||||
for (height = 1; height < MAX_TREE_HEIGHT; height++)
|
||||
{
|
||||
uint nodes_count = get_nodes_count_full_bin_tree(height);
|
||||
|
||||
struct f_tree *tree = get_balanced_tree_with_ranged_values(nodes_count);
|
||||
uint max_value = get_max_value_in_unbalanced_tree(tree, 0);
|
||||
|
||||
show_tree(tree);
|
||||
|
||||
bt_debug("max_value: %u \n", max_value);
|
||||
|
||||
struct f_val needle = {
|
||||
.type = T_INT
|
||||
};
|
||||
uint *i = &needle.val.i;
|
||||
|
||||
for(*i = 0; *i <= max_value; *i += (uint)bt_random()/nodes_count)
|
||||
{
|
||||
struct f_tree *found_tree = find_tree(tree, needle);
|
||||
bt_debug("searching: %u \n", *i);
|
||||
bt_assert(
|
||||
(val_compare(needle, found_tree->from) == 0) || (val_compare(needle, found_tree->to) == 0) ||
|
||||
((val_compare(needle, found_tree->from) == 1) && (val_compare(needle, found_tree->to) == -1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_balancing, "Balancing strong unbalanced trees");
|
||||
bt_test_suite(t_balancing_random, "Balancing random unbalanced trees");
|
||||
bt_test_suite(t_find, "Finding values in trees");
|
||||
bt_test_suite(t_find_ranges, "Finding values in trees with random ranged values");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
184
filter/trie_test.c
Normal file
184
filter/trie_test.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Filters: Utility Functions Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h"
|
||||
|
||||
#include "filter/filter.h"
|
||||
#include "conf/conf.h"
|
||||
|
||||
#define TESTS_NUM 10
|
||||
#define PREFIXES_NUM 10
|
||||
#define PREFIX_TESTS_NUM 10000
|
||||
|
||||
#define BIG_BUFFER_SIZE 10000
|
||||
|
||||
/* Wrapping structure for storing f_prefixes structures in list */
|
||||
struct f_prefix_node {
|
||||
node n;
|
||||
struct f_prefix prefix;
|
||||
};
|
||||
|
||||
static u32
|
||||
xrandom(u32 max)
|
||||
{
|
||||
return (bt_random() % max);
|
||||
}
|
||||
|
||||
static int
|
||||
is_prefix_included(list *prefixes, struct f_prefix *needle)
|
||||
{
|
||||
struct f_prefix_node *n;
|
||||
WALK_LIST(n, *prefixes)
|
||||
{
|
||||
ip6_addr cmask = ip6_mkmask(MIN(n->prefix.net.pxlen, needle->net.pxlen));
|
||||
|
||||
ip6_addr ip = net6_prefix(&n->prefix.net);
|
||||
ip6_addr needle_ip = net6_prefix(&needle->net);
|
||||
|
||||
if ((ipa_compare(ipa_and(ip, cmask), ipa_and(needle_ip, cmask)) == 0) &&
|
||||
(n->prefix.lo <= needle->net.pxlen) && (needle->net.pxlen <= n->prefix.hi))
|
||||
{
|
||||
bt_debug("FOUND\t" PRIip6 "/%d %d-%d\n", ARGip6(net6_prefix(&n->prefix.net)), n->prefix.net.pxlen, n->prefix.lo, n->prefix.hi);
|
||||
return 1; /* OK */
|
||||
}
|
||||
}
|
||||
return 0; /* FAIL */
|
||||
}
|
||||
|
||||
static struct f_prefix
|
||||
get_random_ip6_prefix(void)
|
||||
{
|
||||
struct f_prefix p;
|
||||
u8 pxlen = xrandom(120)+8;
|
||||
ip6_addr ip6 = ip6_build(bt_random(),bt_random(),bt_random(),bt_random());
|
||||
net_addr_ip6 net6 = NET_ADDR_IP6(ip6, pxlen);
|
||||
|
||||
p.net = *((net_addr*) &net6);
|
||||
|
||||
if (bt_random() % 2)
|
||||
{
|
||||
p.lo = 0;
|
||||
p.hi = p.net.pxlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.lo = p.net.pxlen;
|
||||
p.hi = net_max_prefix_length[p.net.type];
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
generate_random_ipv6_prefixes(list *prefixes)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PREFIXES_NUM; i++)
|
||||
{
|
||||
struct f_prefix f = get_random_ip6_prefix();
|
||||
|
||||
struct f_prefix_node *px = calloc(1, sizeof(struct f_prefix_node));
|
||||
px->prefix = f;
|
||||
|
||||
bt_debug("ADD\t" PRIip6 "/%d %d-%d\n", ARGip6(net6_prefix(&px->prefix.net)), px->prefix.net.pxlen, px->prefix.lo, px->prefix.hi);
|
||||
add_tail(prefixes, &px->n);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
t_match_net(void)
|
||||
{
|
||||
bt_bird_init();
|
||||
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||
|
||||
uint round;
|
||||
for (round = 0; round < TESTS_NUM; round++)
|
||||
{
|
||||
list prefixes; /* of structs f_extended_prefix */
|
||||
init_list(&prefixes);
|
||||
struct f_trie *trie = f_new_trie(config->mem, sizeof(struct f_trie_node));
|
||||
|
||||
generate_random_ipv6_prefixes(&prefixes);
|
||||
struct f_prefix_node *n;
|
||||
WALK_LIST(n, prefixes)
|
||||
{
|
||||
trie_add_prefix(trie, &n->prefix.net, n->prefix.lo, n->prefix.hi);
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < PREFIX_TESTS_NUM; i++)
|
||||
{
|
||||
struct f_prefix f = get_random_ip6_prefix();
|
||||
bt_debug("TEST\t" PRIip6 "/%d\n", ARGip6(net6_prefix(&f.net)), f.net.pxlen);
|
||||
|
||||
int should_be = is_prefix_included(&prefixes, &f);
|
||||
int is_there = trie_match_net(trie, &f.net);
|
||||
bt_assert_msg(should_be == is_there, "Prefix " PRIip6 "/%d %s", ARGip6(net6_prefix(&f.net)), f.net.pxlen, (should_be ? "should be found in trie" : "should not be found in trie"));
|
||||
}
|
||||
|
||||
struct f_prefix_node *nxt;
|
||||
WALK_LIST_DELSAFE(n, nxt, prefixes)
|
||||
{
|
||||
free(n);
|
||||
}
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_trie_same(void)
|
||||
{
|
||||
bt_bird_init();
|
||||
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||
|
||||
int round;
|
||||
for (round = 0; round < TESTS_NUM*4; round++)
|
||||
{
|
||||
struct f_trie * trie1 = f_new_trie(config->mem, sizeof(struct f_trie_node));
|
||||
struct f_trie * trie2 = f_new_trie(config->mem, sizeof(struct f_trie_node));
|
||||
|
||||
list prefixes; /* a list of f_extended_prefix structures */
|
||||
init_list(&prefixes);
|
||||
int i;
|
||||
for (i = 0; i < 100; i++)
|
||||
generate_random_ipv6_prefixes(&prefixes);
|
||||
|
||||
struct f_prefix_node *n;
|
||||
WALK_LIST(n, prefixes)
|
||||
{
|
||||
trie_add_prefix(trie1, &n->prefix.net, n->prefix.lo, n->prefix.hi);
|
||||
}
|
||||
WALK_LIST_BACKWARDS(n, prefixes)
|
||||
{
|
||||
trie_add_prefix(trie2, &n->prefix.net, n->prefix.lo, n->prefix.hi);
|
||||
}
|
||||
|
||||
bt_assert(trie_same(trie1, trie2));
|
||||
|
||||
struct f_prefix_node *nxt;
|
||||
WALK_LIST_DELSAFE(n, nxt, prefixes)
|
||||
{
|
||||
free(n);
|
||||
}
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_match_net, "Testing random prefix matching");
|
||||
bt_test_suite(t_trie_same, "A trie filled forward should be same with a trie filled backward.");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
src := bitops.c checksum.c event.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c xmalloc.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
|
||||
tests_src := heap_test.c buffer_test.c event_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c checksum_test.c lists_test.c mac_test.c ip_test.c hash_test.c printf_test.c
|
||||
tests_targets := $(tests_targets) $(tests-target-files)
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
@ -56,7 +56,6 @@ static inline int u64_cmp(u64 i1, u64 i2)
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
|
||||
|
||||
/* Macros for gcc attributes */
|
||||
|
||||
#define NORET __attribute__((noreturn))
|
||||
@ -150,7 +149,7 @@ void bug(const char *msg, ...) NORET;
|
||||
#define L_FATAL "\010" /* Fatal errors */
|
||||
#define L_BUG "\011" /* BIRD bugs */
|
||||
|
||||
void debug(const char *msg, ...); /* Printf to debug output */
|
||||
void debug(const char *msg, ...); /* Printf to debug output */
|
||||
|
||||
/* Debugging */
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef _BIRD_BITOPTS_H_
|
||||
#define _BIRD_BITOPTS_H_
|
||||
|
||||
#include "sysdep/config.h"
|
||||
|
||||
/*
|
||||
* Bit mask operations:
|
||||
*
|
||||
|
123
lib/bitops_test.c
Normal file
123
lib/bitops_test.c
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* BIRD Library -- Generic Bit Operations Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h" /* naive_pow() */
|
||||
|
||||
#include "lib/bitops.h"
|
||||
|
||||
#define MAX_NUM 1000
|
||||
#define CHECK_BIT(var,pos) ((var) & (u32)(1<<(pos)))
|
||||
|
||||
static int
|
||||
t_mkmask(void)
|
||||
{
|
||||
int i;
|
||||
u32 compute, expect;
|
||||
|
||||
bt_assert(u32_mkmask(0) == 0x00000000);
|
||||
for (i = 1; i <= 32; i++)
|
||||
{
|
||||
compute = u32_mkmask(i);
|
||||
expect = (u32) (0xffffffff << (32-i));
|
||||
bt_assert_msg(compute == expect, "u32_mkmask(%d) = 0x%08X, expected 0x%08X", i, compute, expect);
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
u32_masklen_expected(u32 mask)
|
||||
{
|
||||
int j, expect = 0;
|
||||
|
||||
int valid = 0;
|
||||
for (j = 0; j <= 32; j++)
|
||||
if (mask == (j ? (0xffffffff << (32-j)) : 0)) /* Shifting 32-bit value by 32 bits is undefined behavior */
|
||||
valid = 1;
|
||||
|
||||
if (!valid && mask != 0)
|
||||
expect = 255;
|
||||
else
|
||||
for (j = 0; j <= 31; j++)
|
||||
if (CHECK_BIT(mask, (31-j)))
|
||||
expect = j+1;
|
||||
else
|
||||
break;
|
||||
return expect;
|
||||
}
|
||||
|
||||
static void
|
||||
check_mask(u32 mask)
|
||||
{
|
||||
int expected, masklen;
|
||||
|
||||
expected = u32_masklen_expected(mask);
|
||||
masklen = u32_masklen(mask);
|
||||
int ok = (expected == masklen);
|
||||
bt_debug("u32_masklen(Ox%08x) = %d, expected %d %s\n", mask, masklen, expected, ok ? "OK" : "FAIL!");
|
||||
bt_assert(ok);
|
||||
}
|
||||
|
||||
static int
|
||||
t_masklen(void)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
check_mask(0x82828282);
|
||||
check_mask(0x00000000);
|
||||
|
||||
for (i = 0; i <= 32; i++)
|
||||
check_mask(((u32) (i ? (0xffffffff << (32-i)) : 0)) & 0xffffffff); /* Shifting 32-bit value by 32 bits is undefined behavior */
|
||||
|
||||
for (i = 0; i <= MAX_NUM; i++)
|
||||
check_mask(bt_random());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
check_log2(u32 n)
|
||||
{
|
||||
u32 log = u32_log2(n);
|
||||
u32 low = bt_naive_pow(2, log);
|
||||
u32 high = bt_naive_pow(2, log+1);
|
||||
|
||||
bt_assert_msg(n >= low && n < high,
|
||||
"u32_log2(%u) = %u, %u should be in the range <%u, %u)",
|
||||
n, log, n, low, high);
|
||||
}
|
||||
|
||||
static int
|
||||
t_log2(void)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 31; i++)
|
||||
bt_assert(u32_log2(bt_naive_pow(2, i+1)) == i+1);
|
||||
|
||||
for (i = 1; i < MAX_NUM; i++)
|
||||
check_log2(i);
|
||||
|
||||
for (i = 1; i < MAX_NUM; i++)
|
||||
check_log2(((u32) bt_random()) % 0x0fffffff);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_mkmask, "u32_mkmask()");
|
||||
bt_test_suite(t_masklen, "u32_masklen()");
|
||||
bt_test_suite(t_log2, "u32_log2()");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
147
lib/buffer_test.c
Normal file
147
lib/buffer_test.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* BIRD Library -- Buffer Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "lib/buffer.h"
|
||||
|
||||
#define MAX_NUM 33
|
||||
|
||||
typedef BUFFER(int) buffer_int;
|
||||
static int expected[MAX_NUM];
|
||||
static buffer_int buf;
|
||||
static struct pool *buffer_pool;
|
||||
|
||||
static void
|
||||
show_buf(buffer_int *b)
|
||||
{
|
||||
uint i;
|
||||
bt_debug(".used = %d, .size = %d\n", b->used, b->size);
|
||||
|
||||
for (i = 0; i < b->used; i++)
|
||||
bt_debug(" .data[%3u] = %-16d expected %-16d %s\n", i, b->data[i], expected[i], (b->data[i] == expected[i] ? "OK" : "FAIL!"));
|
||||
}
|
||||
|
||||
static void
|
||||
fill_expected_array(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
expected[i] = bt_random();
|
||||
}
|
||||
|
||||
static void
|
||||
init_buffer(void)
|
||||
{
|
||||
resource_init();
|
||||
buffer_pool = &root_pool;
|
||||
BUFFER_INIT(buf, buffer_pool, MAX_NUM);
|
||||
}
|
||||
|
||||
static int
|
||||
is_buffer_as_expected(buffer_int *b)
|
||||
{
|
||||
show_buf(b);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
bt_assert(b->data[i] == expected[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
t_buffer_push(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_buffer();
|
||||
fill_expected_array();
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
BUFFER_PUSH(buf) = expected[i];
|
||||
is_buffer_as_expected(&buf);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_buffer_pop(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_buffer();
|
||||
fill_expected_array();
|
||||
|
||||
/* POP a half of elements */
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
BUFFER_PUSH(buf) = expected[i];
|
||||
for (i = MAX_NUM-1; i >= MAX_NUM/2; i--)
|
||||
BUFFER_POP(buf);
|
||||
for (i = MAX_NUM/2; i < MAX_NUM; i++)
|
||||
BUFFER_PUSH(buf) = expected[i] = bt_random();
|
||||
is_buffer_as_expected(&buf);
|
||||
|
||||
/* POP all of elements */
|
||||
for (i = MAX_NUM-1; i >= 0; i--)
|
||||
BUFFER_POP(buf);
|
||||
bt_assert(buf.used == 0);
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
BUFFER_PUSH(buf) = expected[i];
|
||||
is_buffer_as_expected(&buf);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_buffer_resize(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_buffer();
|
||||
BUFFER_INIT(buf, buffer_pool, 0);
|
||||
fill_expected_array();
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
BUFFER_PUSH(buf) = expected[i];
|
||||
is_buffer_as_expected(&buf);
|
||||
bt_assert(buf.size >= MAX_NUM);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_buffer_flush(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_buffer();
|
||||
fill_expected_array();
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
BUFFER_PUSH(buf) = expected[i];
|
||||
|
||||
BUFFER_FLUSH(buf);
|
||||
bt_assert(buf.used == 0);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_buffer_push, "Pushing new elements");
|
||||
bt_test_suite(t_buffer_pop, "Fill whole buffer (PUSH), a half of elements POP and PUSH new elements");
|
||||
bt_test_suite(t_buffer_resize, "Init a small buffer and try overfill");
|
||||
bt_test_suite(t_buffer_flush, "Fill and flush all elements");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
94
lib/checksum_test.c
Normal file
94
lib/checksum_test.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* BIRD Library -- IP One-Complement Checksum Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "lib/checksum.h"
|
||||
|
||||
#define MAX_NUM 10000
|
||||
|
||||
static u16
|
||||
ipsum_calculate_expected(u32 *a)
|
||||
{
|
||||
int i;
|
||||
u32 sum = 0;
|
||||
|
||||
for(i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
sum += a[i] & 0xffff;
|
||||
bt_debug("low) \t0x%08X \n", sum);
|
||||
|
||||
sum += a[i] >> 16;
|
||||
bt_debug("high) \t0x%08X \n", sum);
|
||||
|
||||
u16 carry = sum >> 16;
|
||||
sum = (sum & 0xffff) + carry;
|
||||
bt_debug("carry) \t0x%08X \n\n", sum);
|
||||
}
|
||||
bt_debug("sum) \t0x%08X \n", sum);
|
||||
|
||||
sum = sum ^ 0xffff;
|
||||
bt_debug("~sum) \t0x%08X \n", sum);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int
|
||||
t_calculate(void)
|
||||
{
|
||||
u32 a[MAX_NUM];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
a[i] = bt_random();
|
||||
|
||||
u16 sum_calculated = ipsum_calculate(a, sizeof(a), NULL);
|
||||
u16 sum_calculated_2 = ipsum_calculate(&a[0], sizeof(u32)*(MAX_NUM/2), &a[MAX_NUM/2], sizeof(u32)*(MAX_NUM - MAX_NUM/2), NULL);
|
||||
bt_assert(sum_calculated == sum_calculated_2);
|
||||
|
||||
u16 sum_expected = ipsum_calculate_expected(a);
|
||||
|
||||
bt_debug("sum_calculated: %08X \n", sum_calculated);
|
||||
bt_debug("sum_expected: %08X \n", sum_expected);
|
||||
|
||||
bt_assert(sum_calculated == sum_expected);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_verify(void)
|
||||
{
|
||||
u32 a[MAX_NUM+1];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
a[i] = bt_random();
|
||||
|
||||
u16 sum = ipsum_calculate_expected(a);
|
||||
|
||||
a[MAX_NUM] = sum;
|
||||
|
||||
bt_assert(ipsum_verify(a, sizeof(a), NULL));
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_calculate, "Checksum of pseudo-random data");
|
||||
bt_test_suite(t_verify, "Verification of pseudo-random data.");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
88
lib/event_test.c
Normal file
88
lib/event_test.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* BIRD Library -- Event Processing Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "lib/net.h"
|
||||
#include "lib/event.h"
|
||||
#include "conf/conf.h"
|
||||
#include "nest/locks.h"
|
||||
#include "sysdep/unix/unix.h"
|
||||
#include "nest/iface.h"
|
||||
#include "nest/route.h"
|
||||
|
||||
#define MAX_NUM 4
|
||||
|
||||
int event_check_points[MAX_NUM];
|
||||
|
||||
#define event_hook_body(num) \
|
||||
do { \
|
||||
bt_debug("Event Hook " #num "\n"); \
|
||||
event_check_points[num] = 1; \
|
||||
bt_assert_msg(event_check_points[num-1], "Events should be run in right order"); \
|
||||
} while (0)
|
||||
|
||||
static void event_hook_1(void *data UNUSED) { event_hook_body(1); }
|
||||
static void event_hook_2(void *data UNUSED) { event_hook_body(2); }
|
||||
static void event_hook_3(void *data UNUSED) { event_hook_body(3); }
|
||||
|
||||
#define schedule_event(num) \
|
||||
do { \
|
||||
struct event *event_##num = ev_new(&root_pool); \
|
||||
event_##num->hook = event_hook_##num; \
|
||||
ev_schedule(event_##num); \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
init_event_check_points(void)
|
||||
{
|
||||
int i;
|
||||
event_check_points[0] = 1;
|
||||
for (i = 1; i < MAX_NUM; i++)
|
||||
event_check_points[i] = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
t_ev_run_list(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
resource_init();
|
||||
olock_init();
|
||||
io_init();
|
||||
rt_init();
|
||||
if_init();
|
||||
// roa_init();
|
||||
config_init();
|
||||
config = config_alloc("");
|
||||
|
||||
init_event_check_points();
|
||||
|
||||
schedule_event(1);
|
||||
schedule_event(2);
|
||||
schedule_event(3);
|
||||
|
||||
ev_run_list(&global_event_list);
|
||||
|
||||
for (i = 1; i < MAX_NUM; i++)
|
||||
bt_assert(event_check_points[i]);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_ev_run_list, "Schedule and run 3 events in right order.");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
||||
|
169
lib/fletcher16_test.c
Normal file
169
lib/fletcher16_test.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* BIRD Library -- Fletcher-16 Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "lib/fletcher16.h"
|
||||
|
||||
static u16
|
||||
straightforward_fletcher16_compute(const char *data)
|
||||
{
|
||||
int count = strlen(data);
|
||||
|
||||
u16 sum1 = 0;
|
||||
u16 sum2 = 0;
|
||||
int index;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
sum1 = (sum1 + data[index]) % 255;
|
||||
sum2 = (sum2 + sum1) % 255;
|
||||
}
|
||||
|
||||
return (sum2 << 8) | sum1;
|
||||
}
|
||||
|
||||
static u16
|
||||
straightforward_fletcher16_checksum(const char *data)
|
||||
{
|
||||
u16 csum;
|
||||
u8 c0,c1,f0,f1;
|
||||
|
||||
csum = straightforward_fletcher16_compute(data);
|
||||
f0 = csum & 0xff;
|
||||
f1 = (csum >> 8) & 0xff;
|
||||
c0 = 0xff - ((f0 + f1) % 0xff);
|
||||
c1 = 0xff - ((f0 + c0) % 0xff);
|
||||
|
||||
return (c1 << 8) | c0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_fletcher16(void *out_, const void *in_, const void *expected_out_)
|
||||
{
|
||||
u16 *out = out_;
|
||||
const char *in = in_;
|
||||
const u16 *expected_out = expected_out_;
|
||||
|
||||
struct fletcher16_context ctxt;
|
||||
|
||||
fletcher16_init(&ctxt);
|
||||
fletcher16_update(&ctxt, in, strlen(in));
|
||||
put_u16(out, fletcher16_compute(&ctxt));
|
||||
|
||||
return (*out == *expected_out) ? BT_SUCCESS : BT_FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
test_fletcher16_checksum(void *out_, const void *in_, const void *expected_out_)
|
||||
{
|
||||
u16 *out = out_;
|
||||
const char *in = in_;
|
||||
const u16 *expected_out = expected_out_;
|
||||
|
||||
struct fletcher16_context ctxt;
|
||||
int len = strlen(in);
|
||||
|
||||
fletcher16_init(&ctxt);
|
||||
fletcher16_update(&ctxt, in, len);
|
||||
put_u16(out, fletcher16_final(&ctxt, len, len));
|
||||
|
||||
return (*out == *expected_out) ? BT_SUCCESS : BT_FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
t_fletcher16_compute(void)
|
||||
{
|
||||
struct bt_pair test_vectors[] = {
|
||||
{
|
||||
.in = "\001\002",
|
||||
.out = & (const u16) { 0x0403 },
|
||||
},
|
||||
{
|
||||
.in = "",
|
||||
.out = & ((const u16) { straightforward_fletcher16_compute("") }),
|
||||
},
|
||||
{
|
||||
.in = "a",
|
||||
.out = & ((const u16) { straightforward_fletcher16_compute("a") }),
|
||||
},
|
||||
{
|
||||
.in = "abcd",
|
||||
.out = & ((const u16) { straightforward_fletcher16_compute("abcd") }),
|
||||
},
|
||||
{
|
||||
.in = "message digest",
|
||||
.out = & ((const u16) { straightforward_fletcher16_compute("message digest") }),
|
||||
},
|
||||
{
|
||||
.in = "abcdefghijklmnopqrstuvwxyz",
|
||||
.out = & ((const u16) { straightforward_fletcher16_compute("abcdefghijklmnopqrstuvwxyz") }),
|
||||
},
|
||||
{
|
||||
.in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
||||
.out = & ((const u16) { straightforward_fletcher16_compute("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") }),
|
||||
},
|
||||
{
|
||||
.in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
|
||||
.out = & ((const u16) { straightforward_fletcher16_compute("12345678901234567890123456789012345678901234567890123456789012345678901234567890") }),
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_fletcher16, bt_fmt_str, bt_fmt_unsigned);
|
||||
}
|
||||
|
||||
static int
|
||||
t_fletcher16_checksum(void)
|
||||
{
|
||||
struct bt_pair test_vectors[] = {
|
||||
{
|
||||
.in = "\001\002",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("\001\002") }),
|
||||
},
|
||||
{
|
||||
.in = "",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("") }),
|
||||
},
|
||||
{
|
||||
.in = "a",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("a") }),
|
||||
},
|
||||
{
|
||||
.in = "abcd",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("abcd") }),
|
||||
},
|
||||
{
|
||||
.in = "message digest",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("message digest") }),
|
||||
},
|
||||
{
|
||||
.in = "abcdefghijklmnopqrstuvwxyz",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("abcdefghijklmnopqrstuvwxyz") }),
|
||||
},
|
||||
{
|
||||
.in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") }),
|
||||
},
|
||||
{
|
||||
.in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
|
||||
.out = & ((const u16) { straightforward_fletcher16_checksum("12345678901234567890123456789012345678901234567890123456789012345678901234567890") }),
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_fletcher16_checksum, bt_fmt_str, bt_fmt_unsigned);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_fletcher16_compute, "Fletcher-16 Compute Tests");
|
||||
bt_test_suite(t_fletcher16_checksum, "Fletcher-16 Checksum Tests");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
305
lib/hash_test.c
Normal file
305
lib/hash_test.c
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* BIRD Library -- Hash Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "lib/hash.h"
|
||||
|
||||
struct test_node {
|
||||
struct test_node *next; /* Hash chain */
|
||||
u32 key;
|
||||
};
|
||||
|
||||
#define TEST_KEY(n) n->key
|
||||
#define TEST_NEXT(n) n->next
|
||||
#define TEST_EQ(n1,n2) n1 == n2
|
||||
#define TEST_FN(n) (n) ^ u32_hash((n))
|
||||
#define TEST_ORDER 13
|
||||
#define TEST_PARAMS /TEST_ORDER, *2, 2, 2, TEST_ORDER, 20
|
||||
#define TEST_REHASH test_rehash
|
||||
|
||||
HASH_DEFINE_REHASH_FN(TEST, struct test_node);
|
||||
|
||||
HASH(struct test_node) hash;
|
||||
struct pool *my_pool;
|
||||
|
||||
#define MAX_NUM (1 << TEST_ORDER)
|
||||
|
||||
struct test_node nodes[MAX_NUM];
|
||||
|
||||
static void
|
||||
print_rate_of_fulfilment(void)
|
||||
{
|
||||
int i;
|
||||
int num_stacked_items = 0;
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
if (!hash.data[i])
|
||||
num_stacked_items++;
|
||||
|
||||
double percent_stacked_items = ((double)num_stacked_items/(double)MAX_NUM)*100.;
|
||||
bt_debug("%d (%.2f %%) chained of %d hashes \n", num_stacked_items, percent_stacked_items, MAX_NUM);
|
||||
}
|
||||
|
||||
#ifdef LOCAL_DEBUG
|
||||
static void
|
||||
dump_nodes(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
bt_debug("nodes[%3d] is at address %14p has .key %3d, .next %14p \n", i, &nodes[i], nodes[i].key, nodes[i].next);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
init_hash_(uint order)
|
||||
{
|
||||
resource_init();
|
||||
my_pool = rp_new(&root_pool, "Test pool");
|
||||
|
||||
HASH_INIT(hash, my_pool, order);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
nodes[i].key = i;
|
||||
nodes[i].next = NULL;
|
||||
}
|
||||
|
||||
bt_debug("MAX_NUM %d \n", MAX_NUM);
|
||||
}
|
||||
|
||||
static void
|
||||
init_hash(void)
|
||||
{
|
||||
init_hash_(TEST_ORDER);
|
||||
}
|
||||
|
||||
static void
|
||||
validate_filled_hash(void)
|
||||
{
|
||||
int i;
|
||||
struct test_node *node;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
node = HASH_FIND(hash, TEST, nodes[i].key);
|
||||
bt_assert_msg(node->key == nodes[i].key, "Hash should be filled, to find (%p) the node[%d] (%p) with .key = %u, .next %p", node, i, &nodes[i], nodes[i].key, nodes[i].next);
|
||||
}
|
||||
|
||||
print_rate_of_fulfilment();
|
||||
}
|
||||
|
||||
static void
|
||||
validate_empty_hash(void)
|
||||
{
|
||||
int i;
|
||||
struct test_node *node;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
node = HASH_FIND(hash, TEST, nodes[i].key);
|
||||
bt_assert_msg(node == NULL, "Hash should be empty, to find (%p) the node[%d] (%p) with .key %u, .next %p", node, i, &nodes[i], nodes[i].key, nodes[i].next);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fill_hash(void)
|
||||
{
|
||||
int i;
|
||||
struct test_node *node;
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
nodes[i].key = i;
|
||||
node = &nodes[i];
|
||||
HASH_INSERT(hash, TEST, node);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
t_insert_find(void)
|
||||
{
|
||||
init_hash();
|
||||
fill_hash();
|
||||
validate_filled_hash();
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_insert_find_random(void)
|
||||
{
|
||||
init_hash();
|
||||
|
||||
int i;
|
||||
struct test_node *node;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
nodes[i].key = bt_random();
|
||||
node = &nodes[i];
|
||||
HASH_INSERT(hash, TEST, node);
|
||||
}
|
||||
|
||||
validate_filled_hash();
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_insert2_find(void)
|
||||
{
|
||||
init_hash_(1);
|
||||
|
||||
int i;
|
||||
struct test_node *node;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
nodes[i].key = i;
|
||||
node = &nodes[i];
|
||||
HASH_INSERT2(hash, TEST, my_pool, node);
|
||||
}
|
||||
bt_assert_msg(hash.order != 1, "The hash should auto-resize from order 2^1. The order of the hash is 2^%u.", hash.order);
|
||||
|
||||
validate_filled_hash();
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_walk(void)
|
||||
{
|
||||
init_hash();
|
||||
fill_hash();
|
||||
|
||||
uint i;
|
||||
uint check[MAX_NUM];
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
check[i] = 0;
|
||||
|
||||
HASH_WALK(hash, next, n)
|
||||
{
|
||||
check[n->key]++;
|
||||
}
|
||||
HASH_WALK_END;
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
bt_assert(check[i] == 1);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_walk_delsafe_delete(void)
|
||||
{
|
||||
init_hash();
|
||||
fill_hash();
|
||||
|
||||
HASH_WALK_DELSAFE(hash, next, n)
|
||||
{
|
||||
HASH_DELETE(hash, TEST, n->key);
|
||||
}
|
||||
HASH_WALK_DELSAFE_END;
|
||||
|
||||
validate_empty_hash();
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_walk_delsafe_remove(void)
|
||||
{
|
||||
init_hash();
|
||||
fill_hash();
|
||||
|
||||
HASH_WALK_DELSAFE(hash, next, n)
|
||||
{
|
||||
HASH_REMOVE(hash, TEST, n);
|
||||
}
|
||||
HASH_WALK_DELSAFE_END;
|
||||
|
||||
validate_empty_hash();
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_walk_delsafe_delete2(void)
|
||||
{
|
||||
init_hash();
|
||||
fill_hash();
|
||||
|
||||
HASH_WALK_DELSAFE(hash, next, n)
|
||||
{
|
||||
HASH_DELETE2(hash, TEST, my_pool, n->key);
|
||||
}
|
||||
HASH_WALK_DELSAFE_END;
|
||||
|
||||
validate_empty_hash();
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_walk_delsafe_remove2(void)
|
||||
{
|
||||
init_hash();
|
||||
fill_hash();
|
||||
|
||||
HASH_WALK_DELSAFE(hash, next, n)
|
||||
{
|
||||
HASH_REMOVE2(hash, TEST, my_pool, n);
|
||||
}
|
||||
HASH_WALK_DELSAFE_END;
|
||||
|
||||
validate_empty_hash();
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_walk_filter(void)
|
||||
{
|
||||
init_hash();
|
||||
fill_hash();
|
||||
|
||||
uint i;
|
||||
uint check[MAX_NUM];
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
check[i] = 0;
|
||||
|
||||
HASH_WALK_FILTER(hash, next, n, m)
|
||||
{
|
||||
bt_assert(n == *m);
|
||||
check[n->key]++;
|
||||
}
|
||||
HASH_WALK_FILTER_END;
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
bt_assert(check[i] == 1);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_insert_find, "HASH_INSERT and HASH_FIND");
|
||||
bt_test_suite(t_insert_find_random, "HASH_INSERT pseudo-random keys and HASH_FIND");
|
||||
bt_test_suite(t_insert2_find, "HASH_INSERT2 and HASH_FIND. HASH_INSERT2 is HASH_INSERT and a smart auto-resize function");
|
||||
bt_test_suite(t_walk, "HASH_WALK");
|
||||
bt_test_suite(t_walk_delsafe_delete, "HASH_WALK_DELSAFE and HASH_DELETE");
|
||||
bt_test_suite(t_walk_delsafe_delete2, "HASH_WALK_DELSAFE and HASH_DELETE2. HASH_DELETE2 is HASH_DELETE and smart auto-resize function");
|
||||
bt_test_suite(t_walk_delsafe_remove, "HASH_WALK_DELSAFE and HASH_REMOVE");
|
||||
bt_test_suite(t_walk_delsafe_remove2, "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function");
|
||||
bt_test_suite(t_walk_filter, "HASH_WALK_FILTER");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
186
lib/heap_test.c
Normal file
186
lib/heap_test.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* BIRD Library -- Universal Heap Macros Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "sysdep/config.h"
|
||||
#include "lib/heap.h"
|
||||
|
||||
#define MAX_NUM 1000
|
||||
#define SPECIAL_KEY -3213
|
||||
|
||||
#define MY_CMP(x, y) ((x) < (y))
|
||||
|
||||
#define MY_HEAP_SWAP(heap,a,b,t) \
|
||||
do { \
|
||||
bt_debug("swap(%u %u) ", a, b); \
|
||||
HEAP_SWAP(heap,a,b,t); \
|
||||
} while(0)
|
||||
|
||||
static int heap[MAX_NUM+1];
|
||||
static uint num;
|
||||
|
||||
/*
|
||||
* A valid heap must follow these rules:
|
||||
* - `num >= 0`
|
||||
* - `heap[i] >= heap[i / 2]` for each `i` in `[2, num]`
|
||||
*/
|
||||
static int
|
||||
is_heap_valid(int heap[], uint num)
|
||||
{
|
||||
uint i;
|
||||
|
||||
if (num > MAX_NUM)
|
||||
return 0;
|
||||
|
||||
for (i = 2; i <= num; i++)
|
||||
if (heap[i] < heap[i / 2])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
show_heap(void)
|
||||
{
|
||||
uint i;
|
||||
bt_debug("\n");
|
||||
bt_debug("numbers %u; ", num);
|
||||
for (i = 0; i <= num; i++)
|
||||
bt_debug("%d ", heap[i]);
|
||||
bt_debug(is_heap_valid(heap, num) ? "OK" : "NON-VALID HEAP!");
|
||||
bt_debug("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
init_heap(void)
|
||||
{
|
||||
uint i;
|
||||
num = 0;
|
||||
heap[0] = SPECIAL_KEY; /* heap[0] should be unused */
|
||||
for (i = 1; i <= MAX_NUM; i++)
|
||||
heap[i] = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
t_heap_insert(void)
|
||||
{
|
||||
uint i;
|
||||
|
||||
init_heap();
|
||||
|
||||
for (i = MAX_NUM; i >= 1; i--)
|
||||
{
|
||||
bt_debug("ins %u at pos %u ", i, MAX_NUM - i);
|
||||
heap[MAX_NUM - i + 1] = i;
|
||||
HEAP_INSERT(heap, ++num, int, MY_CMP, MY_HEAP_SWAP);
|
||||
show_heap();
|
||||
bt_assert(is_heap_valid(heap, num));
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_heap_increase_decrease(void)
|
||||
{
|
||||
uint i;
|
||||
|
||||
t_heap_insert();
|
||||
|
||||
for (i = 1; i <= MAX_NUM; i++)
|
||||
{
|
||||
if ((int)i > heap[i])
|
||||
{
|
||||
bt_debug("inc %u ", i);
|
||||
heap[i] = i;
|
||||
HEAP_INCREASE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
|
||||
}
|
||||
else if ((int)i < heap[i])
|
||||
{
|
||||
bt_debug("dec %u ", i);
|
||||
heap[i] = i;
|
||||
HEAP_INCREASE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
|
||||
}
|
||||
show_heap();
|
||||
bt_assert(is_heap_valid(heap, num));
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_heap_delete(void)
|
||||
{
|
||||
uint i;
|
||||
|
||||
t_heap_insert();
|
||||
|
||||
for (i = 1; i <= num; i++)
|
||||
{
|
||||
bt_debug("del at pos %u ", i);
|
||||
HEAP_DELETE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
|
||||
show_heap();
|
||||
bt_assert(is_heap_valid(heap, num));
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_heap_0(void)
|
||||
{
|
||||
init_heap();
|
||||
t_heap_insert();
|
||||
t_heap_increase_decrease();
|
||||
t_heap_delete();
|
||||
|
||||
return (heap[0] == SPECIAL_KEY) ? BT_SUCCESS : BT_FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
t_heap_insert_random(void)
|
||||
{
|
||||
int i, j;
|
||||
int expected[MAX_NUM+1];
|
||||
|
||||
init_heap();
|
||||
|
||||
for (i = 1; i <= MAX_NUM; i++)
|
||||
{
|
||||
heap[i] = expected[i] = bt_random();
|
||||
HEAP_INSERT(heap, ++num, int, MY_CMP, MY_HEAP_SWAP);
|
||||
show_heap();
|
||||
bt_assert(is_heap_valid(heap, num));
|
||||
}
|
||||
|
||||
for (i = 1; i <= MAX_NUM; i++)
|
||||
for (j = 1; j <= MAX_NUM; j++)
|
||||
if(expected[i] == heap[j])
|
||||
break;
|
||||
else if (j == MAX_NUM)
|
||||
{
|
||||
show_heap();
|
||||
bt_abort_msg("Did not find a number %d in heap.", expected[i]);
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_heap_insert, "Inserting a descending sequence of numbers (the worst case)");
|
||||
bt_test_suite(t_heap_insert_random, "Inserting pseudo-random numbers");
|
||||
bt_test_suite(t_heap_increase_decrease, "Increasing/Decreasing");
|
||||
bt_test_suite(t_heap_delete, "Deleting");
|
||||
bt_test_suite(t_heap_0, "Is a heap[0] really unused?");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
2
lib/ip.c
2
lib/ip.c
@ -306,7 +306,7 @@ ip6_pton(const char *a, ip6_addr *o)
|
||||
|
||||
if (*a == ':' && a[1])
|
||||
a++;
|
||||
else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
|
||||
else if (*a == '.' && (i == 6 || (i < 6 && hfil >= 0)))
|
||||
{ /* Embedded IPv4 address */
|
||||
ip4_addr x;
|
||||
if (!ip4_pton(start, &x))
|
||||
|
161
lib/ip_test.c
Normal file
161
lib/ip_test.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* BIRD Library -- IP address functions Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "lib/ip.h"
|
||||
|
||||
#define IP4_MAX_LEN 16
|
||||
|
||||
static int
|
||||
test_ipa_pton(void *out_, const void *in_, const void *expected_out_)
|
||||
{
|
||||
ip_addr *out = out_;
|
||||
const char *in = in_;
|
||||
const ip_addr *expected_out = expected_out_;
|
||||
|
||||
if (ipa_is_ip4(*expected_out))
|
||||
{
|
||||
ip4_addr ip4;
|
||||
bt_assert(ip4_pton(in, &ip4));
|
||||
*out = ipa_from_ip4(ip4);
|
||||
}
|
||||
else
|
||||
{
|
||||
bt_assert(ip6_pton(in, out));
|
||||
/* ip_addr == ip6_addr */
|
||||
}
|
||||
|
||||
return ipa_equal(*out, *expected_out) ? BT_SUCCESS : BT_FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
t_ip4_pton(void)
|
||||
{
|
||||
struct bt_pair test_vectors[] = {
|
||||
{
|
||||
.in = "192.168.1.128",
|
||||
.out = & ipa_build4(192, 168, 1, 128),
|
||||
},
|
||||
{
|
||||
.in = "255.255.255.255",
|
||||
.out = & ipa_build4(255, 255, 255, 255),
|
||||
},
|
||||
{
|
||||
.in = "0.0.0.0",
|
||||
.out = & ipa_build4(0, 0, 0, 0),
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
|
||||
}
|
||||
|
||||
static int
|
||||
t_ip6_pton(void)
|
||||
{
|
||||
struct bt_pair test_vectors[] = {
|
||||
{
|
||||
.in = "2001:0db8:0000:0000:0000:0000:1428:57ab",
|
||||
.out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
|
||||
},
|
||||
{
|
||||
.in = "2001:0db8:0000:0000:0000::1428:57ab",
|
||||
.out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
|
||||
},
|
||||
{
|
||||
.in = "2001:0db8::1428:57ab",
|
||||
.out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
|
||||
},
|
||||
{
|
||||
.in = "2001:db8::1428:57ab",
|
||||
.out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
|
||||
},
|
||||
{
|
||||
.in = "::1",
|
||||
.out = & ipa_build6(0x00000000, 0x00000000, 0x00000000, 0x00000001),
|
||||
},
|
||||
{
|
||||
.in = "::",
|
||||
.out = & ipa_build6(0x00000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
},
|
||||
{
|
||||
.in = "2605:2700:0:3::4713:93e3",
|
||||
.out = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
|
||||
}
|
||||
|
||||
static int
|
||||
test_ipa_ntop(void *out_, const void *in_, const void *expected_out_)
|
||||
{
|
||||
char *out = out_;
|
||||
const ip_addr *in = in_;
|
||||
const char *expected_out = expected_out_;
|
||||
|
||||
if (ipa_is_ip4(*in))
|
||||
ip4_ntop(ipa_to_ip4(*in), out);
|
||||
else
|
||||
ip6_ntop(ipa_to_ip6(*in), out);
|
||||
|
||||
int result = strncmp(out, expected_out, ipa_is_ip4(*in) ? IP4_MAX_TEXT_LENGTH : IP6_MAX_TEXT_LENGTH) == 0;
|
||||
return result ? BT_SUCCESS : BT_FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
t_ip4_ntop(void)
|
||||
{
|
||||
struct bt_pair test_vectors[] = {
|
||||
{
|
||||
.in = & ipa_build4(192, 168, 1, 128),
|
||||
.out = "192.168.1.128",
|
||||
},
|
||||
{
|
||||
.in = & ipa_build4(255, 255, 255, 255),
|
||||
.out = "255.255.255.255",
|
||||
},
|
||||
{
|
||||
.in = & ipa_build4(0, 0, 0, 1),
|
||||
.out = "0.0.0.1",
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_ipa_ntop, bt_fmt_ipa, bt_fmt_str);
|
||||
}
|
||||
|
||||
static int
|
||||
t_ip6_ntop(void)
|
||||
{
|
||||
struct bt_pair test_vectors[] = {
|
||||
{
|
||||
.in = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
|
||||
.out = "2001:db8::1428:57ab",
|
||||
},
|
||||
{
|
||||
.in = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
|
||||
.out = "2605:2700:0:3::4713:93e3",
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_ipa_ntop, bt_fmt_ipa, bt_fmt_str);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_ip4_pton, "Converting IPv4 string to ip4_addr struct");
|
||||
bt_test_suite(t_ip6_pton, "Converting IPv6 string to ip6_addr struct");
|
||||
bt_test_suite(t_ip4_ntop, "Converting ip4_addr struct to IPv4 string");
|
||||
bt_test_suite(t_ip6_ntop, "Converting ip6_addr struct to IPv6 string");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
||||
|
287
lib/lists_test.c
Normal file
287
lib/lists_test.c
Normal file
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* BIRD Library -- Linked Lists Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "lib/lists.h"
|
||||
|
||||
#define MAX_NUM 1000
|
||||
|
||||
static node nodes[MAX_NUM];
|
||||
static list l;
|
||||
|
||||
static void
|
||||
show_list(void)
|
||||
{
|
||||
bt_debug("\n");
|
||||
bt_debug("list.null is at %p and point to %p\n", &l.null, l.null);
|
||||
bt_debug("list.head is at %p and point to %p\n", &l.head, l.head);
|
||||
bt_debug("list.tail is at %p and point to %p\n", &l.tail, l.tail);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
bt_debug("n[%3i] is at %p\n", i, &nodes[i]);
|
||||
bt_debug(" prev is at %p and point to %p\n", &(nodes[i].prev), nodes[i].prev);
|
||||
bt_debug(" next is at %p and point to %p\n", &(nodes[i].next), nodes[i].next);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
is_filled_list_well_linked(void)
|
||||
{
|
||||
int i;
|
||||
bt_assert(l.head == &nodes[0]);
|
||||
bt_assert(l.tail == &nodes[MAX_NUM-1]);
|
||||
bt_assert((void *) nodes[0].prev == (void *) &l.head);
|
||||
bt_assert((void *) nodes[MAX_NUM-1].next == (void *) &l.null);
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
if (i < (MAX_NUM-1))
|
||||
bt_assert(nodes[i].next == &nodes[i+1]);
|
||||
|
||||
if (i > 0)
|
||||
bt_assert(nodes[i].prev == &nodes[i-1]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
is_empty_list_well_unlinked(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
bt_assert(l.head == NODE &l.null);
|
||||
bt_assert(l.tail == NODE &l.head);
|
||||
bt_assert(EMPTY_LIST(l));
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
bt_assert(nodes[i].next == NULL);
|
||||
bt_assert(nodes[i].prev == NULL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
init_list__(list *l, struct node nodes[])
|
||||
{
|
||||
init_list(l);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
nodes[i].next = NULL;
|
||||
nodes[i].prev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_list_(void)
|
||||
{
|
||||
init_list__(&l, (node *) nodes);
|
||||
}
|
||||
|
||||
static int
|
||||
t_add_tail(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
add_tail(&l, &nodes[i]);
|
||||
bt_debug(".");
|
||||
bt_assert(l.tail == &nodes[i]);
|
||||
bt_assert(l.head == &nodes[0]);
|
||||
bt_assert((void *) nodes[i].next == (void *) &l.null);
|
||||
if (i > 0)
|
||||
{
|
||||
bt_assert(nodes[i-1].next == &nodes[i]);
|
||||
bt_assert(nodes[i].prev == &nodes[i-1]);
|
||||
}
|
||||
}
|
||||
show_list();
|
||||
bt_assert(is_filled_list_well_linked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_add_head(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
for (i = MAX_NUM-1; i >= 0; i--)
|
||||
{
|
||||
add_head(&l, &nodes[i]);
|
||||
bt_debug(".");
|
||||
bt_assert(l.head == &nodes[i]);
|
||||
bt_assert(l.tail == &nodes[MAX_NUM-1]);
|
||||
if (i < MAX_NUM-1)
|
||||
{
|
||||
bt_assert(nodes[i+1].prev == &nodes[i]);
|
||||
bt_assert(nodes[i].next == &nodes[i+1]);
|
||||
}
|
||||
}
|
||||
show_list();
|
||||
bt_assert(is_filled_list_well_linked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
insert_node_(node *n, node *after)
|
||||
{
|
||||
insert_node(n, after);
|
||||
bt_debug(".");
|
||||
}
|
||||
|
||||
static int
|
||||
t_insert_node(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
|
||||
// add first node
|
||||
insert_node_(&nodes[0], NODE &l.head);
|
||||
|
||||
// add odd nodes
|
||||
for (i = 2; i < MAX_NUM; i+=2)
|
||||
insert_node_(&nodes[i], &nodes[i-2]);
|
||||
|
||||
// add even nodes
|
||||
for (i = 1; i < MAX_NUM; i+=2)
|
||||
insert_node_(&nodes[i], &nodes[i-1]);
|
||||
|
||||
bt_debug("\n");
|
||||
bt_assert(is_filled_list_well_linked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_list2(list *l, node nodes[])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
add_tail(l, &nodes[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_list(void)
|
||||
{
|
||||
fill_list2(&l, (node *) nodes);
|
||||
}
|
||||
|
||||
static int
|
||||
t_remove_node(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
|
||||
/* Fill & Remove & Check */
|
||||
fill_list();
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
rem_node(&nodes[i]);
|
||||
bt_assert(is_empty_list_well_unlinked());
|
||||
|
||||
/* Fill & Remove the half of nodes & Check & Remove the rest nodes & Check */
|
||||
fill_list();
|
||||
for (i = 0; i < MAX_NUM; i+=2)
|
||||
rem_node(&nodes[i]);
|
||||
|
||||
int tail_node_index = (MAX_NUM % 2) ? MAX_NUM - 2 : MAX_NUM - 1;
|
||||
bt_assert(l.head == &nodes[1]);
|
||||
bt_assert(l.tail == &nodes[tail_node_index]);
|
||||
bt_assert(nodes[tail_node_index].next == NODE &l.null);
|
||||
|
||||
for (i = 1; i < MAX_NUM; i+=2)
|
||||
{
|
||||
if (i > 1)
|
||||
bt_assert(nodes[i].prev == &nodes[i-2]);
|
||||
if (i < tail_node_index)
|
||||
bt_assert(nodes[i].next == &nodes[i+2]);
|
||||
}
|
||||
|
||||
for (i = 1; i < MAX_NUM; i+=2)
|
||||
rem_node(&nodes[i]);
|
||||
bt_assert(is_empty_list_well_unlinked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_replace_node(void)
|
||||
{
|
||||
node head, inside, tail;
|
||||
|
||||
init_list_();
|
||||
fill_list();
|
||||
|
||||
replace_node(&nodes[0], &head);
|
||||
bt_assert(l.head == &head);
|
||||
bt_assert(head.prev == NODE &l.head);
|
||||
bt_assert(head.next == &nodes[1]);
|
||||
bt_assert(nodes[1].prev == &head);
|
||||
|
||||
replace_node(&nodes[MAX_NUM/2], &inside);
|
||||
bt_assert(nodes[MAX_NUM/2-1].next == &inside);
|
||||
bt_assert(nodes[MAX_NUM/2+1].prev == &inside);
|
||||
bt_assert(inside.prev == &nodes[MAX_NUM/2-1]);
|
||||
bt_assert(inside.next == &nodes[MAX_NUM/2+1]);
|
||||
|
||||
replace_node(&nodes[MAX_NUM-1], &tail);
|
||||
bt_assert(l.tail == &tail);
|
||||
bt_assert(tail.prev == &nodes[MAX_NUM-2]);
|
||||
bt_assert(tail.next == NODE &l.null);
|
||||
bt_assert(nodes[MAX_NUM-2].next == &tail);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_add_tail_list(void)
|
||||
{
|
||||
node nodes2[MAX_NUM];
|
||||
list l2;
|
||||
|
||||
init_list__(&l, (node *) nodes);
|
||||
fill_list2(&l, (node *) nodes);
|
||||
|
||||
init_list__(&l2, (node *) nodes2);
|
||||
fill_list2(&l2, (node *) nodes2);
|
||||
|
||||
add_tail_list(&l, &l2);
|
||||
|
||||
bt_assert(nodes[MAX_NUM-1].next == &nodes2[0]);
|
||||
bt_assert(nodes2[0].prev == &nodes[MAX_NUM-1]);
|
||||
bt_assert(l.tail == &nodes2[MAX_NUM-1]);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_add_tail, "Adding nodes to tail of list");
|
||||
bt_test_suite(t_add_head, "Adding nodes to head of list");
|
||||
bt_test_suite(t_insert_node, "Inserting nodes to list");
|
||||
bt_test_suite(t_remove_node, "Removing nodes from list");
|
||||
bt_test_suite(t_replace_node, "Replacing nodes in list");
|
||||
bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
1159
lib/mac_test.c
Normal file
1159
lib/mac_test.c
Normal file
File diff suppressed because it is too large
Load Diff
149
lib/patmatch_test.c
Normal file
149
lib/patmatch_test.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* BIRD Library -- Pattern Matching Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/string.h"
|
||||
|
||||
#define MATCH (int) { 1 }
|
||||
#define NOMATCH (int) { 0 }
|
||||
|
||||
struct match_pair {
|
||||
byte *pattern;
|
||||
byte *data;
|
||||
};
|
||||
|
||||
static int
|
||||
test_matching(void *out_, const void *in_, const void *expected_out_)
|
||||
{
|
||||
int *out = out_;
|
||||
const struct match_pair *in = in_;
|
||||
const int *expected_out = expected_out_;
|
||||
|
||||
*out = patmatch(in->pattern, in->data);
|
||||
|
||||
return (*out == *expected_out) ? BT_SUCCESS : BT_FAILURE;
|
||||
}
|
||||
|
||||
static void
|
||||
fmt_match_pair(char *buf, size_t size, const void *data)
|
||||
{
|
||||
const struct match_pair *mp = data;
|
||||
snprintf(buf, size, "pattern: '%s', subject: '%s'", mp->pattern, mp->data);
|
||||
}
|
||||
|
||||
static void
|
||||
fmt_match_result(char *buf, size_t size, const void *data)
|
||||
{
|
||||
const int *result = data;
|
||||
snprintf(buf, size, *result ? "match" : "no-match");
|
||||
}
|
||||
|
||||
static int
|
||||
t_matching(void)
|
||||
{
|
||||
struct bt_pair test_vectors[] = {
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "",
|
||||
.data = "",
|
||||
},
|
||||
.out = & MATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "*",
|
||||
.data = "",
|
||||
},
|
||||
.out = & MATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "\\*",
|
||||
.data = "*",
|
||||
},
|
||||
.out = & MATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "\\*",
|
||||
.data = "a",
|
||||
},
|
||||
.out = & NOMATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "?",
|
||||
.data = "",
|
||||
},
|
||||
.out = & NOMATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "abcdefghijklmnopqrstuvwxyz",
|
||||
.data = "abcdefghijklmnopqrstuvwxyz",
|
||||
},
|
||||
.out = & MATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "??????????????????????????",
|
||||
.data = "abcdefghijklmnopqrstuvwxyz",
|
||||
},
|
||||
.out = & MATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "*abcdefghijklmnopqrstuvwxyz*",
|
||||
.data = "abcdefghijklmnopqrstuvwxyz",
|
||||
},
|
||||
.out = & MATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "ab?defg*jklmnop*stu*wxy*z",
|
||||
.data = "abcdefghijklmnopqrstuvwxyz",
|
||||
},
|
||||
.out = & MATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "abcdefghijklmnopqrstuvwxyz",
|
||||
.data = "abcdefghijklmnopqrtuvwxyz",
|
||||
},
|
||||
.out = & NOMATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "abcdefghijklmnopqr?uvwxyz",
|
||||
.data = "abcdefghijklmnopqrstuvwxyz",
|
||||
},
|
||||
.out = & NOMATCH,
|
||||
},
|
||||
{
|
||||
.in = & (struct match_pair) {
|
||||
.pattern = "aa*aaaaa?aaaaaaaaaaaaaaaaaaa",
|
||||
.data = "aaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
.out = & NOMATCH,
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_matching, fmt_match_pair, fmt_match_result);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_matching, "Pattern matching");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
70
lib/printf_test.c
Normal file
70
lib/printf_test.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* BIRD Library -- String Functions Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "lib/string.h"
|
||||
|
||||
#define BSPRINTF(nw, res, buf, fmt, ...) \
|
||||
do { \
|
||||
int n = bsprintf(buf, fmt, ##__VA_ARGS__); \
|
||||
bt_assert_msg(n == nw, "fmt=\"%s\" returns n=%d, want %d", fmt, n, nw); \
|
||||
bt_assert_msg(buf[n] == 0, "fmt=\"%s\" buf[%d] should be \'\\0\', found 0x%02x", fmt, n, buf[n]); \
|
||||
bt_assert_msg(memcmp(buf, res, nw) == 0, "fmt=\"%s\" writes \"%*s\", want \"%*s\"", fmt, (n < nw ? n : nw), buf, nw, res); \
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
t_simple(void)
|
||||
{
|
||||
char buf[256];
|
||||
memset(buf, 0xa5, 256);
|
||||
|
||||
BSPRINTF(0, "", buf, "", NULL);
|
||||
BSPRINTF(1, "%", buf, "%%", NULL);
|
||||
BSPRINTF(2, "%%", buf, "%%%%", NULL);
|
||||
|
||||
BSPRINTF(1, "\x00", buf, "%c", 0);
|
||||
BSPRINTF(1, "@", buf, "@", 64);
|
||||
BSPRINTF(1, "\xff", buf, "%c", 0xff);
|
||||
|
||||
errno = 5;
|
||||
BSPRINTF(18, "Input/output error", buf, "%m");
|
||||
errno = 0;
|
||||
|
||||
BSPRINTF(18, "Input/output error", buf, "%M", 5);
|
||||
|
||||
BSPRINTF(11, "TeSt%StRiNg", buf, "%s", "TeSt%StRiNg");
|
||||
|
||||
if (sizeof(void *) == 4)
|
||||
BSPRINTF(8, "1a15600d", buf, "%p", (void *) 0x1a15600d);
|
||||
else
|
||||
BSPRINTF(16, "00000fee1a15600d", buf, "%p", (void *) 0xfee1a15600d);
|
||||
|
||||
long ln = 0;
|
||||
BSPRINTF(10, "TeStStRiNg", buf, "TeStS%lntRiNg", &ln);
|
||||
bt_assert_msg(ln == 5, "fmt=\"TeStS%%lntRiNg\", &ln makes ln=%ld, want 5", ln);
|
||||
|
||||
BSPRINTF(2, "%d", buf, "%%d", 1);
|
||||
BSPRINTF(1, "1", buf, "%d", 1);
|
||||
BSPRINTF(2, "+1", buf, "%+d", 1);
|
||||
BSPRINTF(2, " 1", buf, "% d", 1);
|
||||
BSPRINTF(2, "-1", buf, "%d", -1);
|
||||
BSPRINTF(11, "-2147483648", buf, "%d", -2147483648);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_simple, "printf without varargs");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
384
lib/slist_test.c
Normal file
384
lib/slist_test.c
Normal file
@ -0,0 +1,384 @@
|
||||
/*
|
||||
* BIRD Library -- Safe Linked Lists Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
|
||||
#include "lib/slists.h"
|
||||
|
||||
#define MAX_NUM 1000
|
||||
|
||||
static snode nodes[MAX_NUM];
|
||||
static slist lst;
|
||||
|
||||
static void
|
||||
show_list(void)
|
||||
{
|
||||
bt_debug("\n");
|
||||
bt_debug("list.null is at %p and point to %p \n", &lst.null, lst.null);
|
||||
bt_debug("list.head is at %p and point to %p \n", &lst.head, lst.head);
|
||||
bt_debug("list.tail is at %p and point to %p \n", &lst.tail, lst.tail);
|
||||
bt_debug("list.tail_readers is at %p and point to %p \n", &lst.tail_readers, lst.tail_readers);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
bt_debug("n[%3i] is at %p, .prev (%p) points to %p, .next (%p) points to %p, .readers (%p) points to %p \n",
|
||||
i, &nodes[i], &(nodes[i].prev), nodes[i].prev, &(nodes[i].next), nodes[i].next, &(nodes[i].readers), nodes[i].readers);
|
||||
}
|
||||
|
||||
static int
|
||||
is_filled_list_well_linked(void)
|
||||
{
|
||||
int i;
|
||||
bt_assert(lst.head == &nodes[0]);
|
||||
bt_assert(lst.tail == &nodes[MAX_NUM-1]);
|
||||
bt_assert((void *) nodes[0].prev == (void *) &lst.head);
|
||||
bt_assert((void *) nodes[MAX_NUM-1].next == (void *) &lst.null);
|
||||
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
if (i < (MAX_NUM-1))
|
||||
bt_assert(nodes[i].next == &nodes[i+1]);
|
||||
|
||||
if (i > 0)
|
||||
bt_assert(nodes[i].prev == &nodes[i-1]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
is_empty_list_well_unlinked(void)
|
||||
{
|
||||
bt_assert(lst.head == SNODE &lst.null);
|
||||
bt_assert(lst.tail == SNODE &lst.head);
|
||||
|
||||
bt_assert(EMPTY_SLIST(lst));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
init_list__(slist *l, struct snode nodes[])
|
||||
{
|
||||
s_init_list(l);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
nodes[i].next = NULL;
|
||||
nodes[i].prev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_list_(void)
|
||||
{
|
||||
init_list__(&lst, nodes);
|
||||
}
|
||||
|
||||
static int
|
||||
t_add_tail(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
{
|
||||
s_add_tail(&lst, &nodes[i]);
|
||||
bt_debug(".");
|
||||
bt_assert(lst.tail == &nodes[i]);
|
||||
bt_assert(lst.head == &nodes[0]);
|
||||
bt_assert((void *) nodes[i].next == (void *) &lst.null);
|
||||
if (i > 0)
|
||||
{
|
||||
bt_assert(nodes[i-1].next == &nodes[i]);
|
||||
bt_assert(nodes[i].prev == &nodes[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
bt_assert(is_filled_list_well_linked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_add_head(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
for (i = MAX_NUM-1; i >= 0; i--)
|
||||
{
|
||||
s_add_head(&lst, &nodes[i]);
|
||||
bt_debug(".");
|
||||
bt_assert(lst.head == &nodes[i]);
|
||||
bt_assert(lst.tail == &nodes[MAX_NUM-1]);
|
||||
if (i < MAX_NUM-1)
|
||||
{
|
||||
bt_assert(nodes[i+1].prev == &nodes[i]);
|
||||
bt_assert(nodes[i].next == &nodes[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
bt_assert(is_filled_list_well_linked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
insert_node_(snode *n, snode *after)
|
||||
{
|
||||
s_insert_node(n, after);
|
||||
bt_debug(".");
|
||||
}
|
||||
|
||||
static int
|
||||
t_insert_node(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
|
||||
// add first node
|
||||
insert_node_(&nodes[0], SNODE &lst.head);
|
||||
|
||||
// add odd nodes
|
||||
for (i = 2; i < MAX_NUM; i+=2)
|
||||
insert_node_(&nodes[i], &nodes[i-2]);
|
||||
|
||||
// add even nodes
|
||||
for (i = 1; i < MAX_NUM; i+=2)
|
||||
insert_node_(&nodes[i], &nodes[i-1]);
|
||||
|
||||
bt_debug("\n");
|
||||
bt_assert(is_filled_list_well_linked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_list2(slist *l, snode nodes[])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
s_add_tail(l, &nodes[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_list(void)
|
||||
{
|
||||
fill_list2(&lst, SNODE nodes);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
t_remove_node(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_list_();
|
||||
|
||||
/* Fill & Remove & Check */
|
||||
fill_list();
|
||||
for (i = 0; i < MAX_NUM; i++)
|
||||
s_rem_node(&nodes[i]);
|
||||
bt_assert(is_empty_list_well_unlinked());
|
||||
|
||||
/* Fill & Remove the half of nodes & Check & Remove the rest nodes & Check */
|
||||
fill_list();
|
||||
for (i = 0; i < MAX_NUM; i+=2)
|
||||
s_rem_node(&nodes[i]);
|
||||
|
||||
int tail_node_index = (MAX_NUM % 2) ? MAX_NUM - 2 : MAX_NUM - 1;
|
||||
bt_assert(lst.head == &nodes[1]);
|
||||
bt_assert(lst.tail == &nodes[tail_node_index]);
|
||||
bt_assert(nodes[tail_node_index].next == SNODE &lst.null);
|
||||
|
||||
for (i = 1; i < MAX_NUM; i+=2)
|
||||
{
|
||||
if (i > 1)
|
||||
bt_assert(nodes[i].prev == &nodes[i-2]);
|
||||
if (i < tail_node_index)
|
||||
bt_assert(nodes[i].next == &nodes[i+2]);
|
||||
}
|
||||
|
||||
for (i = 1; i < MAX_NUM; i+=2)
|
||||
s_rem_node(&nodes[i]);
|
||||
bt_assert(is_empty_list_well_unlinked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_add_tail_list(void)
|
||||
{
|
||||
snode nodes2[MAX_NUM];
|
||||
slist l2;
|
||||
|
||||
init_list__(&lst, SNODE &nodes);
|
||||
fill_list2(&lst, SNODE &nodes);
|
||||
|
||||
init_list__(&l2, SNODE &nodes2);
|
||||
fill_list2(&l2, SNODE &nodes2);
|
||||
|
||||
s_add_tail_list(&lst, &l2);
|
||||
|
||||
bt_assert(nodes[MAX_NUM-1].next == &nodes2[0]);
|
||||
bt_assert(nodes2[0].prev == &nodes[MAX_NUM-1]);
|
||||
bt_assert(lst.tail == &nodes2[MAX_NUM-1]);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
dump(const char *str, slist *a)
|
||||
{
|
||||
snode *x;
|
||||
|
||||
bt_debug("%s \n", str);
|
||||
for (x = SHEAD(*a); x; x = x->next)
|
||||
{
|
||||
siterator *i, *j;
|
||||
bt_debug("%p", x);
|
||||
j = (siterator *) x;
|
||||
for (i = x->readers; i; i = i->next)
|
||||
{
|
||||
if (i->prev != j)
|
||||
bt_debug(" ???");
|
||||
j = i;
|
||||
bt_debug(" [%p:%p]", i, i->node);
|
||||
}
|
||||
bt_debug("\n");
|
||||
}
|
||||
bt_debug("---\n");
|
||||
}
|
||||
|
||||
static int
|
||||
t_iterator_walk(void)
|
||||
{
|
||||
snode *node;
|
||||
siterator iter;
|
||||
|
||||
init_list_();
|
||||
fill_list();
|
||||
|
||||
int k;
|
||||
int i = 0;
|
||||
|
||||
show_list();
|
||||
|
||||
s_init(&iter, &lst);
|
||||
WALK_SLIST(node, lst)
|
||||
{
|
||||
s_get(&iter);
|
||||
s_put(&iter, node);
|
||||
bt_debug("node->readers: %p, iter: %p, nodes[%d].readers: %p, node: %p, nodes[i]: %p, node->next: %p \n",
|
||||
node->readers, &iter, i, nodes[i].readers, node, &(nodes[i]), node->next);
|
||||
bt_assert(node->readers == &iter);
|
||||
bt_assert(node->readers == nodes[i].readers);
|
||||
bt_assert(node == &(nodes[i]));
|
||||
for (k = 0; k < MAX_NUM; k++)
|
||||
if (k != i)
|
||||
bt_assert(nodes[k].readers == NULL);
|
||||
|
||||
dump("",&lst);
|
||||
i++;
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_original(void)
|
||||
{
|
||||
slist a, b;
|
||||
snode *x, *y;
|
||||
siterator i, j;
|
||||
|
||||
s_init_list(&a);
|
||||
s_init_list(&b);
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&a, x);
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&a, x);
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&a, x);
|
||||
dump("1", &a);
|
||||
|
||||
s_init(&i, &a);
|
||||
s_init(&j, &a);
|
||||
dump("2", &a);
|
||||
|
||||
x = s_get(&i);
|
||||
bt_debug("Got %p\n", x);
|
||||
dump("3", &a);
|
||||
|
||||
s_put(&i, x->next);
|
||||
dump("4", &a);
|
||||
|
||||
y = s_get(&j);
|
||||
while (y)
|
||||
{
|
||||
s_put(&j, y);
|
||||
dump("5*", &a);
|
||||
y = s_get(&j)->next;
|
||||
}
|
||||
|
||||
dump("5 done", &a);
|
||||
|
||||
s_rem_node(a.head->next);
|
||||
dump("6 (deletion)", &a);
|
||||
|
||||
s_put(&i, s_get(&i)->next);
|
||||
dump("6 (relink)", &a);
|
||||
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&b, x);
|
||||
dump("7 (second list)", &b);
|
||||
|
||||
s_add_tail_list(&b, &a);
|
||||
dump("8 (after merge)", &b);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_safe_del_walk(void)
|
||||
{
|
||||
init_list_();
|
||||
fill_list();
|
||||
|
||||
show_list();
|
||||
|
||||
snode *node, *node_next;
|
||||
WALK_SLIST_DELSAFE(node,node_next, lst)
|
||||
{
|
||||
bt_debug("Will remove node %p \n", node);
|
||||
s_rem_node(SNODE node);
|
||||
}
|
||||
bt_assert(is_empty_list_well_unlinked());
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_add_tail, "Adding nodes to tail of list");
|
||||
bt_test_suite(t_add_head, "Adding nodes to head of list");
|
||||
bt_test_suite(t_insert_node, "Inserting nodes to list");
|
||||
bt_test_suite(t_remove_node, "Removing nodes from list");
|
||||
bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
|
||||
bt_test_suite(t_iterator_walk, "Iterator walk");
|
||||
bt_test_suite(t_safe_del_walk, "WALK_SLIST_DELSAFE and s_rem_node all nodes");
|
||||
bt_test_suite(t_original, "The original BIRD test suit for SLIST");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
82
lib/slists.c
82
lib/slists.c
@ -150,85 +150,3 @@ s_add_tail_list(slist *to, slist *l)
|
||||
to->tail = q;
|
||||
s_merge((snode *) &l->null, (snode *) &to->null);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include "lib/resource.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void dump(char *c, slist *a)
|
||||
{
|
||||
snode *x;
|
||||
|
||||
puts(c);
|
||||
for(x=SHEAD(*a); x; x=x->next)
|
||||
{
|
||||
siterator *i, *j;
|
||||
printf("%p", x);
|
||||
j = (siterator *) x;
|
||||
for(i=x->readers; i; i=i->next)
|
||||
{
|
||||
if (i->prev != j)
|
||||
printf(" ???");
|
||||
j = i;
|
||||
printf(" [%p:%p]", i, i->node);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
puts("---");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
slist a, b;
|
||||
snode *x, *y;
|
||||
siterator i, j;
|
||||
|
||||
s_init_list(&a);
|
||||
s_init_list(&b);
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&a, x);
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&a, x);
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&a, x);
|
||||
dump("1", &a);
|
||||
|
||||
s_init(&i, &a);
|
||||
s_init(&j, &a);
|
||||
dump("2", &a);
|
||||
|
||||
x = s_get(&i);
|
||||
printf("Got %p\n", x);
|
||||
dump("3", &a);
|
||||
|
||||
s_put(&i, x->next);
|
||||
dump("4", &a);
|
||||
|
||||
y = s_get(&j);
|
||||
while (y)
|
||||
{
|
||||
s_put(&j, y);
|
||||
dump("5*", &a);
|
||||
y = s_get(&j)->next;
|
||||
}
|
||||
|
||||
dump("5 done", &a);
|
||||
|
||||
s_rem_node(a.head->next);
|
||||
dump("6 (deletion)", &a);
|
||||
|
||||
s_put(&i, s_get(&i)->next);
|
||||
dump("6 (relink)", &a);
|
||||
|
||||
x = xmalloc(sizeof(*x));
|
||||
s_add_tail(&b, x);
|
||||
dump("7 (second list)", &b);
|
||||
|
||||
s_add_tail_list(&b, &a);
|
||||
dump("8 (after merge)", &b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2,3 +2,7 @@ src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_src := a-set_test.c a-path_test.c
|
||||
tests_targets := $(tests_targets) $(tests-target-files)
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#define put_as put_u32
|
||||
#define get_as get_u32
|
||||
#define BS 4
|
||||
#define BS 4 /* Base (default) size of ASN (autonomous system number) */
|
||||
|
||||
struct adata *
|
||||
as_path_prepend(struct linpool *pool, struct adata *olda, u32 as)
|
||||
@ -499,7 +499,6 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
|
||||
* (auxiliary position after last real position in AS path)
|
||||
* is marked.
|
||||
*/
|
||||
|
||||
int
|
||||
as_path_match(struct adata *path, struct f_path_mask *mask)
|
||||
{
|
||||
|
214
nest/a-path_test.c
Normal file
214
nest/a-path_test.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* BIRD -- Path Operations Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h"
|
||||
|
||||
#include "nest/route.h"
|
||||
#include "nest/attrs.h"
|
||||
#include "lib/resource.h"
|
||||
|
||||
#define TESTS_NUM 30
|
||||
#define AS_PATH_LENGTH 1000
|
||||
|
||||
#if AS_PATH_LENGTH > AS_PATH_MAXLEN
|
||||
#warning "AS_PATH_LENGTH should be <= AS_PATH_MAXLEN"
|
||||
#endif
|
||||
|
||||
static int
|
||||
t_as_path_match(void)
|
||||
{
|
||||
resource_init();
|
||||
|
||||
int round;
|
||||
for (round = 0; round < TESTS_NUM; round++)
|
||||
{
|
||||
struct adata empty_as_path = {};
|
||||
struct adata *as_path = &empty_as_path;
|
||||
u32 first_prepended, last_prepended;
|
||||
first_prepended = last_prepended = 0;
|
||||
struct linpool *lp = lp_new(&root_pool, 0);
|
||||
|
||||
struct f_path_mask mask[AS_PATH_LENGTH] = {};
|
||||
int i;
|
||||
for (i = 0; i < AS_PATH_LENGTH; i++)
|
||||
{
|
||||
u32 val = bt_random();
|
||||
as_path = as_path_prepend(lp, as_path, val);
|
||||
bt_debug("Prepending ASN: %10u \n", val);
|
||||
|
||||
if (i == 0)
|
||||
first_prepended = val;
|
||||
if (i == AS_PATH_LENGTH-1)
|
||||
last_prepended = val;
|
||||
|
||||
mask[i].kind = PM_ASN;
|
||||
mask[i].val = val;
|
||||
if (i)
|
||||
mask[i].next = &mask[i-1];
|
||||
}
|
||||
|
||||
bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path");
|
||||
|
||||
u32 asn;
|
||||
|
||||
bt_assert(as_path_get_first(as_path, &asn));
|
||||
bt_assert_msg(asn == last_prepended, "as_path_get_first() should return the last prepended ASN");
|
||||
|
||||
bt_assert(as_path_get_last(as_path, &asn));
|
||||
bt_assert_msg(asn == first_prepended, "as_path_get_last() should return the first prepended ASN");
|
||||
|
||||
rfree(lp);
|
||||
}
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_path_format(void)
|
||||
{
|
||||
resource_init();
|
||||
|
||||
struct adata empty_as_path = {};
|
||||
struct adata *as_path = &empty_as_path;
|
||||
struct linpool *lp = lp_new(&root_pool, 0);
|
||||
|
||||
uint i;
|
||||
for (i = 4294967285; i <= 4294967294; i++)
|
||||
{
|
||||
as_path = as_path_prepend(lp, as_path, i);
|
||||
bt_debug("Prepending ASN: %10u \n", i);
|
||||
}
|
||||
|
||||
#define BUFFER_SIZE 26
|
||||
byte buf[BUFFER_SIZE] = {};
|
||||
as_path_format(as_path, buf, BUFFER_SIZE);
|
||||
bt_assert_msg(strcmp(buf, "4294967294 4294967293 ...") == 0, "Buffer(%zu): '%s'", strlen(buf), buf);
|
||||
|
||||
#define SMALL_BUFFER_SIZE 25
|
||||
byte buf2[SMALL_BUFFER_SIZE] = {};
|
||||
as_path_format(as_path, buf2, SMALL_BUFFER_SIZE);
|
||||
bt_assert_msg(strcmp(buf2, "4294967294 ...") == 0, "Small Buffer(%zu): '%s'", strlen(buf2), buf2);
|
||||
|
||||
rfree(lp);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
count_asn_in_array(const u32 *array, u32 asn)
|
||||
{
|
||||
int counts_of_contains = 0;
|
||||
int u;
|
||||
for (u = 0; u < AS_PATH_LENGTH; u++)
|
||||
if (array[u] == asn)
|
||||
counts_of_contains++;
|
||||
return counts_of_contains;
|
||||
}
|
||||
|
||||
static int
|
||||
t_path_include(void)
|
||||
{
|
||||
resource_init();
|
||||
|
||||
struct adata empty_as_path = {};
|
||||
struct adata *as_path = &empty_as_path;
|
||||
struct linpool *lp = lp_new(&root_pool, 0);
|
||||
|
||||
u32 as_nums[AS_PATH_LENGTH] = {};
|
||||
int i;
|
||||
for (i = 0; i < AS_PATH_LENGTH; i++)
|
||||
{
|
||||
u32 val = bt_random();
|
||||
as_nums[i] = val;
|
||||
as_path = as_path_prepend(lp, as_path, val);
|
||||
}
|
||||
|
||||
for (i = 0; i < AS_PATH_LENGTH; i++)
|
||||
{
|
||||
int counts_of_contains = count_asn_in_array(as_nums, as_nums[i]);
|
||||
bt_assert_msg(as_path_contains(as_path, as_nums[i], counts_of_contains), "AS Path should contains %d-times number %d", counts_of_contains, as_nums[i]);
|
||||
|
||||
bt_assert(as_path_filter(lp, as_path, NULL, as_nums[i], 0) != NULL);
|
||||
bt_assert(as_path_filter(lp, as_path, NULL, as_nums[i], 1) != NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < 10000; i++)
|
||||
{
|
||||
u32 test_val = bt_random();
|
||||
int counts_of_contains = count_asn_in_array(as_nums, test_val);
|
||||
int result = as_path_contains(as_path, test_val, (counts_of_contains == 0 ? 1 : counts_of_contains));
|
||||
|
||||
if (counts_of_contains)
|
||||
bt_assert_msg(result, "As path should contain %d-times the number %u", counts_of_contains, test_val);
|
||||
else
|
||||
bt_assert_msg(result == 0, "As path should not contain the number %u", test_val);
|
||||
}
|
||||
|
||||
rfree(lp);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_as_path_converting(void)
|
||||
{
|
||||
resource_init();
|
||||
|
||||
struct adata empty_as_path = {};
|
||||
struct adata *as_path = &empty_as_path;
|
||||
struct linpool *lp = lp_new(&root_pool, 0);
|
||||
#define AS_PATH_LENGTH_FOR_CONVERTING_TEST 10
|
||||
|
||||
int i;
|
||||
for (i = 0; i < AS_PATH_LENGTH_FOR_CONVERTING_TEST; i++)
|
||||
as_path = as_path_prepend(lp, as_path, i);
|
||||
|
||||
bt_debug("data length: %u \n", as_path->length);
|
||||
|
||||
byte buffer[100] = {};
|
||||
int used_size = as_path_convert_to_new(as_path, buffer, AS_PATH_LENGTH_FOR_CONVERTING_TEST-1);
|
||||
bt_debug("as_path_convert_to_new: len %d \n%s\n", used_size, buffer);
|
||||
for (i = 0; i < used_size; i++)
|
||||
{
|
||||
bt_debug("\\03%d", buffer[i]);
|
||||
}
|
||||
bt_debug("\n");
|
||||
bt_assert(memcmp(buffer,
|
||||
"\032\039\030\030\030\030\030\030\030\039\030\030\030\030\030\030\030\038\030\030\030\030\030\030"
|
||||
"\030\037\030\030\030\030\030\030\030\036\030\030\030\030",
|
||||
38));
|
||||
|
||||
bzero(buffer, sizeof(buffer));
|
||||
int new_used;
|
||||
used_size = as_path_convert_to_old(as_path, buffer, &new_used);
|
||||
bt_debug("as_path_convert_to_old: len %d, new_used: %d \n", used_size, new_used);
|
||||
for (i = 0; i < used_size; i++)
|
||||
{
|
||||
bt_debug("\\03%d", buffer[i]);
|
||||
}
|
||||
bt_debug("\n");
|
||||
bt_assert(memcmp(buffer,
|
||||
"\032\0310\030\039\030\038\030\037\030\036\030\035\030\034\030\033\030\032\030\031\030\030",
|
||||
22));
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_as_path_match, "Testing AS path matching and some a-path utilities.");
|
||||
bt_test_suite(t_path_format, "Testing formating as path into byte buffer");
|
||||
bt_test_suite(t_path_include, "Testing including a AS number in AS path");
|
||||
bt_test_suite(t_as_path_converting, "Testing as_path_convert_to_*() output constancy");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
260
nest/a-set_test.c
Normal file
260
nest/a-set_test.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* BIRD -- Set/Community-list Operations Tests
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h"
|
||||
|
||||
#include "lib/net.h"
|
||||
#include "nest/route.h"
|
||||
#include "nest/attrs.h"
|
||||
#include "lib/resource.h"
|
||||
|
||||
#define SET_SIZE 10
|
||||
static struct adata *set_sequence; /* <0; SET_SIZE) */
|
||||
static struct adata *set_sequence_same; /* <0; SET_SIZE) */
|
||||
static struct adata *set_sequence_higher; /* <SET_SIZE; 2*SET_SIZE) */
|
||||
static struct adata *set_random;
|
||||
|
||||
#define BUFFER_SIZE 1000
|
||||
static byte buf[BUFFER_SIZE] = {};
|
||||
|
||||
#define SET_SIZE_FOR_FORMAT_OUTPUT 10
|
||||
|
||||
struct linpool *lp;
|
||||
|
||||
enum set_type
|
||||
{
|
||||
SET_TYPE_INT,
|
||||
SET_TYPE_EC
|
||||
};
|
||||
|
||||
static void
|
||||
generate_set_sequence(enum set_type type)
|
||||
{
|
||||
struct adata empty_as_path = {};
|
||||
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
|
||||
lp = lp_new(&root_pool, 0);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
{
|
||||
if (type == SET_TYPE_INT)
|
||||
{
|
||||
set_sequence = int_set_add(lp, set_sequence, i);
|
||||
set_sequence_same = int_set_add(lp, set_sequence_same, i);
|
||||
set_sequence_higher = int_set_add(lp, set_sequence_higher, i + SET_SIZE);
|
||||
set_random = int_set_add(lp, set_random, bt_random());
|
||||
}
|
||||
else if (type == SET_TYPE_EC)
|
||||
{
|
||||
set_sequence = ec_set_add(lp, set_sequence, i);
|
||||
set_sequence_same = ec_set_add(lp, set_sequence_same, i);
|
||||
set_sequence_higher = ec_set_add(lp, set_sequence_higher, i + SET_SIZE);
|
||||
set_random = ec_set_add(lp, set_random, (bt_random() << 32 | bt_random()));
|
||||
}
|
||||
else
|
||||
bt_abort_msg("This should be unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SET INT TESTS
|
||||
*/
|
||||
|
||||
static int
|
||||
t_set_int_contains(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
|
||||
bt_assert(int_set_get_size(set_sequence) == SET_SIZE);
|
||||
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
bt_assert(int_set_contains(set_sequence, i));
|
||||
bt_assert(int_set_contains(set_sequence, -1) == 0);
|
||||
bt_assert(int_set_contains(set_sequence, SET_SIZE) == 0);
|
||||
|
||||
int *data = int_set_get_data(set_sequence);
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
bt_assert_msg(data[i] == i, "(data[i] = %d) == i = %d)", data[i], i);
|
||||
|
||||
rfree(lp);
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_set_int_union(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
|
||||
struct adata *set_union;
|
||||
set_union = int_set_union(lp, set_sequence, set_sequence_same);
|
||||
bt_assert(int_set_get_size(set_union) == SET_SIZE);
|
||||
bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
|
||||
|
||||
set_union = int_set_union(lp, set_sequence, set_sequence_higher);
|
||||
bt_assert_msg(int_set_get_size(set_union) == SET_SIZE*2, "int_set_get_size(set_union) %d, SET_SIZE*2 %d", int_set_get_size(set_union), SET_SIZE*2);
|
||||
bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
|
||||
|
||||
rfree(lp);
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_set_int_format(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
|
||||
set_sequence->length = 4 * SET_SIZE_FOR_FORMAT_OUTPUT; /* dirty */
|
||||
bt_assert(int_set_format(set_sequence, 0, 0, buf, BUFFER_SIZE) == 0);
|
||||
bt_assert(strcmp(buf, "0.0.0.0 0.0.0.1 0.0.0.2 0.0.0.3 0.0.0.4 0.0.0.5 0.0.0.6 0.0.0.7 0.0.0.8 0.0.0.9") == 0);
|
||||
|
||||
bzero(buf, BUFFER_SIZE);
|
||||
bt_assert(int_set_format(set_sequence, 0, 2, buf, BUFFER_SIZE) == 0);
|
||||
bt_assert(strcmp(buf, "0.0.0.2 0.0.0.3 0.0.0.4 0.0.0.5 0.0.0.6 0.0.0.7 0.0.0.8 0.0.0.9") == 0);
|
||||
|
||||
bzero(buf, BUFFER_SIZE);
|
||||
bt_assert(int_set_format(set_sequence, 1, 0, buf, BUFFER_SIZE) == 0);
|
||||
bt_assert(strcmp(buf, "(0,0) (0,1) (0,2) (0,3) (0,4) (0,5) (0,6) (0,7) (0,8) (0,9)") == 0);
|
||||
|
||||
rfree(lp);
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_set_int_delete(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
|
||||
struct adata *deleting_sequence = set_sequence;
|
||||
u32 i;
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
{
|
||||
deleting_sequence = int_set_del(lp, deleting_sequence, i);
|
||||
bt_assert_msg(int_set_get_size(deleting_sequence) == (int) (SET_SIZE-1-i),
|
||||
"int_set_get_size(deleting_sequence) %d == SET_SIZE-1-i %d",
|
||||
int_set_get_size(deleting_sequence),
|
||||
SET_SIZE-1-i);
|
||||
}
|
||||
|
||||
bt_assert(int_set_get_size(set_sequence) == SET_SIZE);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* SET EC TESTS
|
||||
*/
|
||||
|
||||
static int
|
||||
t_set_ec_contains(void)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_EC);
|
||||
|
||||
bt_assert(ec_set_get_size(set_sequence) == SET_SIZE);
|
||||
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
bt_assert(ec_set_contains(set_sequence, i));
|
||||
bt_assert(ec_set_contains(set_sequence, -1) == 0);
|
||||
bt_assert(ec_set_contains(set_sequence, SET_SIZE) == 0);
|
||||
|
||||
// int *data = ec_set_get_data(set_sequence);
|
||||
// for (i = 0; i < SET_SIZE; i++)
|
||||
// bt_assert_msg(data[i] == (SET_SIZE-1-i), "(data[i] = %d) == ((SET_SIZE-1-i) = %d)", data[i], SET_SIZE-1-i);
|
||||
|
||||
rfree(lp);
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_set_ec_union(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_EC);
|
||||
|
||||
struct adata *set_union;
|
||||
set_union = ec_set_union(lp, set_sequence, set_sequence_same);
|
||||
bt_assert(ec_set_get_size(set_union) == SET_SIZE);
|
||||
bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
|
||||
|
||||
set_union = ec_set_union(lp, set_sequence, set_sequence_higher);
|
||||
bt_assert_msg(ec_set_get_size(set_union) == SET_SIZE*2, "ec_set_get_size(set_union) %d, SET_SIZE*2 %d", ec_set_get_size(set_union), SET_SIZE*2);
|
||||
bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
|
||||
|
||||
rfree(lp);
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_set_ec_format(void)
|
||||
{
|
||||
resource_init();
|
||||
|
||||
struct adata empty_as_path = {};
|
||||
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
|
||||
lp = lp_new(&root_pool, 0);
|
||||
|
||||
u64 i = 0;
|
||||
set_sequence = ec_set_add(lp, set_sequence, i);
|
||||
for (i = 1; i < SET_SIZE_FOR_FORMAT_OUTPUT; i++)
|
||||
set_sequence = ec_set_add(lp, set_sequence, i + ((i%2) ? ((u64)EC_RO << 48) : ((u64)EC_RT << 48)));
|
||||
|
||||
bt_assert(ec_set_format(set_sequence, 0, buf, BUFFER_SIZE) == 0);
|
||||
bt_assert_msg(strcmp(buf, "(unknown 0x0, 0, 0) (ro, 0, 1) (rt, 0, 2) (ro, 0, 3) (rt, 0, 4) (ro, 0, 5) (rt, 0, 6) (ro, 0, 7) (rt, 0, 8) (ro, 0, 9)") == 0,
|
||||
"ec_set_format() returns '%s'", buf);
|
||||
|
||||
rfree(lp);
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
t_set_ec_delete(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_EC);
|
||||
|
||||
struct adata *deleting_sequence = set_sequence;
|
||||
u32 i;
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
{
|
||||
deleting_sequence = ec_set_del(lp, deleting_sequence, i);
|
||||
bt_assert_msg(ec_set_get_size(deleting_sequence) == (int) (SET_SIZE-1-i),
|
||||
"ec_set_get_size(deleting_sequence) %d == SET_SIZE-1-i %d",
|
||||
ec_set_get_size(deleting_sequence), SET_SIZE-1-i);
|
||||
}
|
||||
|
||||
bt_assert(ec_set_get_size(set_sequence) == SET_SIZE);
|
||||
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
|
||||
bt_test_suite(t_set_int_contains, "Testing sets of integers: contains, get_data");
|
||||
bt_test_suite(t_set_int_format, "Testing sets of integers: format");
|
||||
bt_test_suite(t_set_int_union, "Testing sets of integers: union");
|
||||
bt_test_suite(t_set_int_delete, "Testing sets of integers: delete");
|
||||
|
||||
bt_test_suite(t_set_ec_contains, "Testing sets of Extended Community values: contains, get_data");
|
||||
bt_test_suite(t_set_ec_format, "Testing sets of Extended Community values: format");
|
||||
bt_test_suite(t_set_ec_union, "Testing sets of Extended Community values: union");
|
||||
bt_test_suite(t_set_ec_delete, "Testing sets of Extended Community values: delete");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
#define _BIRD_IFACE_H_
|
||||
|
||||
#include "lib/lists.h"
|
||||
#include "lib/ip.h"
|
||||
|
||||
extern list iface_list;
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "lib/lists.h"
|
||||
#include "lib/resource.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
//#include "nest/protocol.h"
|
||||
#include "lib/net.h"
|
||||
|
||||
struct ea_list;
|
||||
struct protocol;
|
||||
|
@ -2,3 +2,5 @@ src := bfd.c io.c packets.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
@ -2,3 +2,5 @@ src := attrs.c bgp.c packets.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
@ -2,3 +2,5 @@ src := dbdes.c hello.c iface.c lsack.c lsalib.c lsreq.c lsupd.c neighbor.c ospf.
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
@ -1921,7 +1921,7 @@ rt_sync(struct ospf_proto *p)
|
||||
/* This is used for forced reload of routes */
|
||||
int reload = (p->calcrt == 2);
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation");
|
||||
OSPF_TRACE(D_EVENTS, "Starting routing table synchronization");
|
||||
|
||||
DBG("Now syncing my rt table with nest's\n");
|
||||
FIB_ITERATE_INIT(&fit, fib);
|
||||
|
@ -2,3 +2,5 @@ src := pipe.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
@ -2,3 +2,5 @@ src := packets.c radv.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
@ -311,7 +311,7 @@ radv_check_active(struct proto_radv *ra)
|
||||
if (!radv_trigger_valid(cf))
|
||||
return 1;
|
||||
|
||||
struct channel *c =ra->p.main_channel;
|
||||
struct channel *c = ra->p.main_channel;
|
||||
return rt_examine(c->table, &cf->trigger, &ra->p, c->out_filter);
|
||||
}
|
||||
|
||||
|
@ -2,3 +2,5 @@ src := packets.c rip.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
@ -2,3 +2,5 @@ src := static.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
@ -67,4 +67,7 @@
|
||||
/* We have stdint.h */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* We have execinfo.h */
|
||||
#undef HAVE_EXECINFO_H
|
||||
|
||||
#define CONFIG_PATH ?
|
||||
|
@ -3,3 +3,4 @@ obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(conf-y-targets): $(s)krt-sock.Y
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
@ -2,3 +2,5 @@ src := netlink.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(conf-y-targets): $(s)netlink.Y
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
@ -3,3 +3,6 @@ obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
$(conf-y-targets): $(s)krt.Y
|
||||
|
||||
src := $(filter-out main.c, $(src))
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
3
test/Makefile
Normal file
3
test/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
src := birdtest.c bt-utils.c
|
||||
obj := $(src-o-files)
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
488
test/birdtest.c
Normal file
488
test/birdtest.c
Normal file
@ -0,0 +1,488 @@
|
||||
/*
|
||||
* BIRD -- Unit Test Framework (BIRD Test)
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "lib/string.h"
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
#define BACKTRACE_MAX_LINES 100
|
||||
|
||||
#define sprintf_concat(s, format, ...) \
|
||||
snprintf(s + strlen(s), sizeof(s) - strlen(s), format, ##__VA_ARGS__)
|
||||
|
||||
static const char *request;
|
||||
static int list_tests;
|
||||
static int do_core;
|
||||
static int no_fork;
|
||||
static int no_timeout;
|
||||
static int is_terminal; /* Whether stdout is a live terminal or pipe redirect */
|
||||
|
||||
uint bt_verbose;
|
||||
const char *bt_filename;
|
||||
const char *bt_test_id;
|
||||
|
||||
int bt_result; /* Overall program run result */
|
||||
int bt_suite_result; /* One suit result */
|
||||
char bt_out_fmt_buf[1024]; /* Temporary memory buffer for output of testing function */
|
||||
|
||||
long int
|
||||
bt_random(void)
|
||||
{
|
||||
/* Seeded in bt_init() */
|
||||
long int rand_low, rand_high;
|
||||
|
||||
rand_low = random();
|
||||
rand_high = random();
|
||||
return (rand_low & 0xffff) | ((rand_high & 0xffff) << 16);
|
||||
}
|
||||
|
||||
void
|
||||
bt_init(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
|
||||
srandom(BT_RANDOM_SEED);
|
||||
|
||||
bt_verbose = 0;
|
||||
bt_filename = argv[0];
|
||||
bt_result = BT_SUCCESS;
|
||||
bt_test_id = NULL;
|
||||
is_terminal = isatty(fileno(stdout));
|
||||
|
||||
while ((c = getopt(argc, argv, "lcftv")) >= 0)
|
||||
switch (c)
|
||||
{
|
||||
case 'l':
|
||||
list_tests = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
do_core = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
no_fork = 1;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
no_timeout = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
bt_verbose++;
|
||||
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] [-vvv] [<test_suit_name>]\n", argv[0]);
|
||||
printf("Options: \n");
|
||||
printf(" -l List all test suite names and descriptions \n");
|
||||
printf(" -c Force unlimit core dumps (needs root privileges) \n");
|
||||
printf(" -f No forking \n");
|
||||
printf(" -t No timeout limit \n");
|
||||
printf(" -v More verbosity, maximum is 3 -vvv \n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
static void
|
||||
bt_dump_backtrace(void)
|
||||
{
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
void *buf[BACKTRACE_MAX_LINES];
|
||||
char **pp_backtrace;
|
||||
int lines, j;
|
||||
|
||||
if (!bt_verbose)
|
||||
return;
|
||||
|
||||
lines = backtrace(buf, BACKTRACE_MAX_LINES);
|
||||
bt_log("backtrace() returned %d addresses", lines);
|
||||
|
||||
pp_backtrace = backtrace_symbols(buf, lines);
|
||||
if (pp_backtrace == NULL)
|
||||
{
|
||||
perror("backtrace_symbols");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (j = 0; j < lines; j++)
|
||||
bt_log("%s", pp_backtrace[j]);
|
||||
|
||||
free(pp_backtrace);
|
||||
#endif /* HAVE_EXECINFO_H */
|
||||
}
|
||||
|
||||
static
|
||||
int bt_run_test_fn(int (*fn)(const void *), const void *fn_arg, int timeout)
|
||||
{
|
||||
int result;
|
||||
alarm(timeout);
|
||||
|
||||
if (fn_arg)
|
||||
result = fn(fn_arg);
|
||||
else
|
||||
result = ((int (*)(void))fn)();
|
||||
|
||||
if (bt_suite_result != BT_SUCCESS)
|
||||
result = BT_FAILURE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint
|
||||
get_num_terminal_cols(void)
|
||||
{
|
||||
struct winsize w = {};
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
uint cols = w.ws_col;
|
||||
return (cols > 0 ? cols : 80);
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_log_result - pretty print of test result
|
||||
* @result: BT_SUCCESS or BT_FAILURE
|
||||
* @fmt: a description message (could be long, over more lines)
|
||||
* @argptr: variable argument list
|
||||
*
|
||||
* This function is used for pretty printing of test results on all verbose
|
||||
* levels.
|
||||
*/
|
||||
static void
|
||||
bt_log_result(int result, const char *fmt, va_list argptr)
|
||||
{
|
||||
char fmt_buf[BT_BUFFER_SIZE];
|
||||
char msg_buf[BT_BUFFER_SIZE];
|
||||
char *pos;
|
||||
|
||||
snprintf(msg_buf, sizeof(msg_buf), "%s%s%s%s",
|
||||
bt_filename,
|
||||
bt_test_id ? ": " : "",
|
||||
bt_test_id ? bt_test_id : "",
|
||||
(fmt && strlen(fmt) > 0) ? ": " : "");
|
||||
pos = msg_buf + strlen(msg_buf);
|
||||
|
||||
vsnprintf(pos, sizeof(msg_buf) - (pos - msg_buf), fmt, argptr);
|
||||
|
||||
/* 'll' means here Last Line */
|
||||
uint cols = get_num_terminal_cols();
|
||||
uint ll_len = (strlen(msg_buf) % cols) + BT_PROMPT_OK_FAIL_STRLEN;
|
||||
uint ll_offset = (ll_len / get_num_terminal_cols() + 1) * cols - BT_PROMPT_OK_FAIL_STRLEN;
|
||||
uint offset = ll_offset + (strlen(msg_buf) / cols) * cols;
|
||||
snprintf(fmt_buf, sizeof(fmt_buf), "%%-%us%%s\n", offset);
|
||||
|
||||
const char *result_str = is_terminal ? BT_PROMPT_OK : BT_PROMPT_OK_NO_COLOR;
|
||||
if (result != BT_SUCCESS)
|
||||
result_str = is_terminal ? BT_PROMPT_FAIL : BT_PROMPT_FAIL_NO_COLOR;
|
||||
|
||||
printf(fmt_buf, msg_buf, result_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_log_overall_result - pretty print of suite case result
|
||||
* @result: BT_SUCCESS or BT_FAILURE
|
||||
* @fmt: a description message (could be long, over more lines)
|
||||
* ...: variable argument list
|
||||
*
|
||||
* This function is used for pretty printing of test suite case result.
|
||||
*/
|
||||
static void
|
||||
bt_log_overall_result(int result, const char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
bt_log_result(result, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_log_suite_result - pretty print of suite case result
|
||||
* @result: BT_SUCCESS or BT_FAILURE
|
||||
* @fmt: a description message (could be long, over more lines)
|
||||
* ...: variable argument list
|
||||
*
|
||||
* This function is used for pretty printing of test suite case result.
|
||||
*/
|
||||
void
|
||||
bt_log_suite_result(int result, const char *fmt, ...)
|
||||
{
|
||||
if(bt_verbose >= BT_VERBOSE_SUITE || result == BT_FAILURE)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
bt_log_result(result, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_log_suite_case_result - pretty print of suite result
|
||||
* @result: BT_SUCCESS or BT_FAILURE
|
||||
* @fmt: a description message (could be long, over more lines)
|
||||
* ...: variable argument list
|
||||
*
|
||||
* This function is used for pretty printing of test suite result.
|
||||
*/
|
||||
void
|
||||
bt_log_suite_case_result(int result, const char *fmt, ...)
|
||||
{
|
||||
if(bt_verbose >= BT_VERBOSE_SUITE_CASE)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
bt_log_result(result, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
bt_test_suite_base(int (*fn)(const void *), const char *id, const void *fn_arg, int forked, int timeout, const char *dsc, ...)
|
||||
{
|
||||
if (list_tests)
|
||||
{
|
||||
printf("%28s - ", id);
|
||||
va_list args;
|
||||
va_start(args, dsc);
|
||||
vprintf(dsc, args);
|
||||
va_end(args);
|
||||
printf("\n");
|
||||
return BT_SUCCESS;
|
||||
}
|
||||
|
||||
if (no_fork)
|
||||
forked = 0;
|
||||
|
||||
if (no_timeout)
|
||||
timeout = 0;
|
||||
|
||||
if (request && strcmp(id, request))
|
||||
return BT_SUCCESS;
|
||||
|
||||
bt_suite_result = BT_SUCCESS;
|
||||
bt_test_id = id;
|
||||
|
||||
if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL)
|
||||
bt_log("Starting");
|
||||
|
||||
if (!forked)
|
||||
{
|
||||
bt_suite_result = bt_run_test_fn(fn, fn_arg, timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
pid_t pid = fork();
|
||||
bt_syscall(pid < 0, "fork");
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
/* child of fork */
|
||||
_exit(bt_run_test_fn(fn, fn_arg, timeout));
|
||||
}
|
||||
|
||||
int s;
|
||||
int rv = waitpid(pid, &s, 0);
|
||||
bt_syscall(rv < 0, "waitpid");
|
||||
|
||||
if (WIFEXITED(s))
|
||||
{
|
||||
/* Normal exit */
|
||||
bt_suite_result = WEXITSTATUS(s);
|
||||
}
|
||||
else if (WIFSIGNALED(s))
|
||||
{
|
||||
/* Stopped by signal */
|
||||
bt_suite_result = BT_FAILURE;
|
||||
|
||||
int sn = WTERMSIG(s);
|
||||
if (sn == SIGALRM)
|
||||
{
|
||||
bt_log("Timeout expired");
|
||||
}
|
||||
else if (sn == SIGSEGV)
|
||||
{
|
||||
bt_log("Segmentation fault");
|
||||
bt_dump_backtrace();
|
||||
}
|
||||
else if (sn != SIGABRT)
|
||||
bt_log("Signal %d received", sn);
|
||||
}
|
||||
|
||||
if (WCOREDUMP(s) && bt_verbose)
|
||||
bt_log("Core dumped");
|
||||
}
|
||||
|
||||
if (bt_suite_result == BT_FAILURE)
|
||||
bt_result = BT_FAILURE;
|
||||
|
||||
bt_log_suite_result(bt_suite_result, NULL);
|
||||
bt_test_id = NULL;
|
||||
|
||||
return bt_suite_result;
|
||||
}
|
||||
|
||||
int
|
||||
bt_exit_value(void)
|
||||
{
|
||||
if (!list_tests || (list_tests && bt_result != BT_SUCCESS))
|
||||
bt_log_overall_result(bt_result, "");
|
||||
return bt_result == BT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_assert_batch__ - test a batch of inputs/outputs tests
|
||||
* @opts: includes all necessary data
|
||||
*
|
||||
* Should be called using macro bt_assert_batch().
|
||||
* Returns BT_SUCCESS or BT_FAILURE.
|
||||
*/
|
||||
int
|
||||
bt_assert_batch__(struct bt_batch *opts)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < opts->ndata; i++)
|
||||
{
|
||||
int bt_suit_case_result = opts->test_fn(opts->out_buf, opts->data[i].in, opts->data[i].out);
|
||||
|
||||
if (bt_suit_case_result == BT_FAILURE)
|
||||
bt_suite_result = BT_FAILURE;
|
||||
|
||||
char b[BT_BUFFER_SIZE];
|
||||
snprintf(b, sizeof(b), "%s(", opts->test_fn_name);
|
||||
|
||||
opts->in_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].in);
|
||||
sprintf_concat(b, ") gives ");
|
||||
opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->out_buf);
|
||||
|
||||
if (bt_suit_case_result == BT_FAILURE)
|
||||
{
|
||||
sprintf_concat(b, ", but expecting is ");
|
||||
opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].out);
|
||||
}
|
||||
|
||||
bt_log_suite_case_result(bt_suit_case_result, "%s", b);
|
||||
}
|
||||
|
||||
return bt_suite_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_fmt_str - formating string into output buffer
|
||||
* @buf: buffer for write
|
||||
* @size: empty size in @buf
|
||||
* @data: null-byte terminated string
|
||||
*
|
||||
* This function can be used with bt_assert_batch() function.
|
||||
* Input @data should be const char * string.
|
||||
*/
|
||||
void
|
||||
bt_fmt_str(char *buf, size_t size, const void *data)
|
||||
{
|
||||
const byte *s = data;
|
||||
|
||||
snprintf(buf, size, "\"");
|
||||
while (*s)
|
||||
{
|
||||
snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(*s) ? "%c" : "\\%03u", *s);
|
||||
s++;
|
||||
}
|
||||
snprintf(buf+strlen(buf), size-strlen(buf), "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_fmt_unsigned - formating unsigned int into output buffer
|
||||
* @buf: buffer for write
|
||||
* @size: empty size in @buf
|
||||
* @data: unsigned number
|
||||
*
|
||||
* This function can be used with bt_assert_batch() function.
|
||||
*/
|
||||
void
|
||||
bt_fmt_unsigned(char *buf, size_t size, const void *data)
|
||||
{
|
||||
const uint *n = data;
|
||||
snprintf(buf, size, "0x%x (%u)", *n, *n);
|
||||
}
|
||||
|
||||
/**
|
||||
* bt_fmt_ipa - formating ip_addr into output buffer
|
||||
* @buf: buffer for write
|
||||
* @size: empty size in @buf
|
||||
* @data: should be struct ip_addr *
|
||||
*
|
||||
* This function can be used with bt_assert_batch() function.
|
||||
*/
|
||||
void
|
||||
bt_fmt_ipa(char *buf, size_t size, const void *data)
|
||||
{
|
||||
const ip_addr *ip = data;
|
||||
bsnprintf(buf, size, "%I", *ip);
|
||||
}
|
||||
|
||||
int
|
||||
bt_is_char(byte c)
|
||||
{
|
||||
return (c >= (byte) 32 && c <= (byte) 126);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mock-ups of all necessary public functions in main.c
|
||||
*/
|
||||
|
||||
char *bird_name;
|
||||
void async_config(void) {}
|
||||
void async_dump(void) {}
|
||||
void async_shutdown(void) {}
|
||||
void cmd_check_config(char *name UNUSED) {}
|
||||
void cmd_reconfig(char *name UNUSED, int type UNUSED, int timeout UNUSED) {}
|
||||
void cmd_reconfig_confirm(void) {}
|
||||
void cmd_reconfig_undo(void) {}
|
||||
void cmd_shutdown(void) {}
|
||||
void cmd_reconfig_undo_notify(void) {}
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/net.h"
|
||||
#include "conf/conf.h"
|
||||
void sysdep_preconfig(struct config *c UNUSED) {}
|
||||
int sysdep_commit(struct config *new UNUSED, struct config *old UNUSED) { return 0; }
|
||||
void sysdep_shutdown_done(void) {}
|
||||
|
||||
#include "nest/cli.h"
|
||||
int cli_get_command(cli *c UNUSED) { return 0; }
|
||||
void cli_write_trigger(cli *c UNUSED) {}
|
||||
cli *cmd_reconfig_stored_cli;
|
183
test/birdtest.h
Normal file
183
test/birdtest.h
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* BIRD -- Unit Test Framework (BIRD Test)
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _BIRDTEST_H_
|
||||
#define _BIRDTEST_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
|
||||
|
||||
extern int bt_result;
|
||||
extern int bt_suite_result;
|
||||
extern char bt_out_fmt_buf[1024];
|
||||
|
||||
extern uint bt_verbose;
|
||||
#define BT_VERBOSE_NO 0
|
||||
#define BT_VERBOSE_SUITE 1
|
||||
#define BT_VERBOSE_SUITE_CASE 2
|
||||
#define BT_VERBOSE_ABSOLUTELY_ALL 3
|
||||
|
||||
extern const char *bt_filename;
|
||||
extern const char *bt_test_id;
|
||||
|
||||
void bt_init(int argc, char *argv[]);
|
||||
int bt_exit_value(void);
|
||||
int bt_test_suite_base(int (*test_fn)(const void *), const char *test_id, const void *test_fn_argument, int forked, int timeout, const char *dsc, ...);
|
||||
long int bt_random(void);
|
||||
|
||||
void bt_log_suite_result(int result, const char *fmt, ...);
|
||||
void bt_log_suite_case_result(int result, const char *fmt, ...);
|
||||
|
||||
#define BT_SUCCESS 42 /* 1 is too usual, filter quitbird returns 1 too */
|
||||
#define BT_FAILURE 0
|
||||
|
||||
#define BT_TIMEOUT 5 /* Default timeout in seconds */
|
||||
#define BT_FORKING 1 /* Forking is enabled in default */
|
||||
|
||||
#define BT_RANDOM_SEED 982451653
|
||||
|
||||
#define BT_BUFFER_SIZE 10000
|
||||
|
||||
#define BT_PROMPT_GREEN "\e[1;32m"
|
||||
#define BT_PROMPT_RED "\e[1;31m"
|
||||
#define BT_PROMPT_NORMAL "\e[0m"
|
||||
#define BT_PROMPT_OK " [" BT_PROMPT_GREEN " OK " BT_PROMPT_NORMAL "] "
|
||||
#define BT_PROMPT_OK_NO_COLOR " [" " OK " "] "
|
||||
#define BT_PROMPT_FAIL " [" BT_PROMPT_RED "FAIL" BT_PROMPT_NORMAL "] "
|
||||
#define BT_PROMPT_FAIL_NO_COLOR " [" "FAIL" "] "
|
||||
#define BT_PROMPT_OK_FAIL_STRLEN 8 /* strlen ' [FAIL] ' */
|
||||
|
||||
#define bt_test_suite(fn, dsc, ...) \
|
||||
bt_test_suite_extra(fn, BT_FORKING, BT_TIMEOUT, dsc, ##__VA_ARGS__)
|
||||
|
||||
#define bt_test_suite_extra(fn, f, t, dsc, ...) \
|
||||
bt_test_suite_base((int (*)(const void *))fn, #fn, NULL, f, t, dsc, ##__VA_ARGS__)
|
||||
|
||||
#define bt_test_suite_arg(fn, arg, dsc, ...) \
|
||||
bt_test_suite_arg_extra(fn, arg, BT_FORKING, BT_TIMEOUT, dsc, ##__VA_ARGS__)
|
||||
|
||||
#define bt_test_suite_arg_extra(fn, arg, f, t, dsc, ...) \
|
||||
bt_test_suite_base(fn, #fn, arg, f, t, dsc, ##__VA_ARGS__)
|
||||
|
||||
#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_log(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (bt_test_id) \
|
||||
printf("%s: %s: " format "\n", bt_filename, bt_test_id, ##__VA_ARGS__); \
|
||||
else \
|
||||
printf("%s: " format "\n", bt_filename, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define bt_debug(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL) \
|
||||
printf(format, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define bt_assert(test) \
|
||||
bt_assert_msg(test, "Assertion (%s) at %s:%d", #test, __FILE__, __LINE__)
|
||||
|
||||
#define bt_assert_msg(test, format, ...) \
|
||||
do \
|
||||
{ \
|
||||
int bt_suit_case_result = BT_SUCCESS; \
|
||||
if ((test) == 0) \
|
||||
{ \
|
||||
bt_result = BT_FAILURE; \
|
||||
bt_suite_result = BT_FAILURE; \
|
||||
bt_suit_case_result = BT_FAILURE; \
|
||||
} \
|
||||
bt_log_suite_case_result(bt_suit_case_result, 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)
|
||||
|
||||
#define bt_sprintf_concat(s, format, ...) \
|
||||
snprintf(s + strlen(s), sizeof(s) - strlen(s), format, ##__VA_ARGS__)
|
||||
|
||||
struct bt_pair {
|
||||
const void *in;
|
||||
const void *out;
|
||||
};
|
||||
|
||||
/* Data structure used by bt_assert_batch() function */
|
||||
struct bt_batch {
|
||||
/* in_fmt / out_fmt - formating data
|
||||
* @buf: buffer for write stringified @data
|
||||
* @size: empty size in @buf
|
||||
* @data: data for stringify
|
||||
*
|
||||
* There are some build-in functions, see bt_fmt_* functions */
|
||||
void (*in_fmt)(char *buf, size_t size, const void *data);
|
||||
void (*out_fmt)(char *buf, size_t size, const void *data);
|
||||
|
||||
/* Temporary output buffer */
|
||||
void *out_buf;
|
||||
|
||||
/* test_fn - testing function
|
||||
* @out: output data from tested function
|
||||
* @in: data for input
|
||||
* @expected_out: expected data from tested function
|
||||
*
|
||||
* Input arguments should not be stringified using in_fmt() or out_fmt()
|
||||
* function already. This function should return only BT_SUCCESS or
|
||||
* BT_FAILURE */
|
||||
int (*test_fn)(void *out, const void *in, const void *expected_out);
|
||||
|
||||
/* Name of testing function @test_fn */
|
||||
const char *test_fn_name;
|
||||
|
||||
/* Number of items in data*/
|
||||
int ndata;
|
||||
|
||||
/* Array of input and expected output pairs */
|
||||
struct bt_pair *data;
|
||||
};
|
||||
|
||||
void bt_fmt_str(char *buf, size_t size, const void *data);
|
||||
void bt_fmt_unsigned(char *buf, size_t size, const void *data);
|
||||
void bt_fmt_ipa(char *buf, size_t size, const void *data);
|
||||
int bt_assert_batch__(struct bt_batch *opts);
|
||||
int bt_is_char(byte c);
|
||||
|
||||
#define bt_assert_batch(data__, fn__, in_fmt__, out_fmt__) \
|
||||
bt_assert_batch__(& (struct bt_batch) { \
|
||||
.data = data__, \
|
||||
.ndata = ARRAY_SIZE(data__), \
|
||||
.test_fn = fn__, \
|
||||
.test_fn_name = #fn__, \
|
||||
.in_fmt = in_fmt__, \
|
||||
.out_fmt = out_fmt__, \
|
||||
.out_buf = bt_out_fmt_buf, /* Global memory for this usage */ \
|
||||
})
|
||||
|
||||
#endif /* _BIRDTEST_H_ */
|
223
test/bt-utils.c
Normal file
223
test/bt-utils.c
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* BIRD Test -- Utils for testing parsing configuration file
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h"
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "nest/route.h"
|
||||
#include "nest/protocol.h"
|
||||
|
||||
#include "sysdep/unix/unix.h"
|
||||
#include "sysdep/unix/krt.h"
|
||||
|
||||
#include "nest/iface.h"
|
||||
#include "nest/locks.h"
|
||||
|
||||
#include "filter/filter.h"
|
||||
|
||||
#define BETWEEN(a, b, c) (((a) >= (b)) && ((a) <= (c)))
|
||||
|
||||
static const byte *bt_config_parse_pos;
|
||||
static uint bt_config_parse_remain_len;
|
||||
|
||||
/* This is cf_read_hook for hard-coded text configuration */
|
||||
static int
|
||||
cf_static_read(byte *dest, uint max_len, int fd UNUSED)
|
||||
{
|
||||
if (max_len > bt_config_parse_remain_len)
|
||||
max_len = bt_config_parse_remain_len;
|
||||
memcpy(dest, bt_config_parse_pos, max_len);
|
||||
bt_config_parse_pos += max_len;
|
||||
bt_config_parse_remain_len -= max_len;
|
||||
return max_len;
|
||||
}
|
||||
|
||||
/* This is cf_read_hook for reading configuration files,
|
||||
* function is copied from main.c, cf_read() */
|
||||
static int
|
||||
cf_file_read(byte *dest, uint max_len, int fd)
|
||||
{
|
||||
int l = read(fd, dest, max_len);
|
||||
if (l < 0)
|
||||
cf_error("Read error");
|
||||
return l;
|
||||
}
|
||||
|
||||
void
|
||||
bt_bird_init(void)
|
||||
{
|
||||
if(bt_verbose)
|
||||
log_init_debug("");
|
||||
log_switch(bt_verbose != 0, NULL, NULL);
|
||||
|
||||
resource_init();
|
||||
olock_init();
|
||||
io_init();
|
||||
rt_init();
|
||||
if_init();
|
||||
config_init();
|
||||
|
||||
protos_build();
|
||||
proto_build(&proto_unix_kernel);
|
||||
proto_build(&proto_unix_iface);
|
||||
}
|
||||
|
||||
void bt_bird_cleanup(void)
|
||||
{
|
||||
for (int i = 0; i < EAP_MAX; i++)
|
||||
attr_class_to_protocol[i] = NULL;
|
||||
|
||||
config = new_config = NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
bt_load_file(const char *filename, int quiet)
|
||||
{
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (!quiet)
|
||||
bt_assert_msg(f != NULL, "Open %s", filename);
|
||||
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long file_size_ = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (file_size_ < 0)
|
||||
return NULL;
|
||||
|
||||
size_t file_size = file_size_;
|
||||
size_t read_size = 0;
|
||||
|
||||
char *file_body = mb_allocz(&root_pool, file_size+1);
|
||||
|
||||
/* XXX: copied from cf-lex.c */
|
||||
errno=0;
|
||||
while ((read_size += fread(file_body+read_size, 1, file_size-read_size, f)) != file_size && ferror(f))
|
||||
{
|
||||
bt_debug("iteration \n");
|
||||
if(errno != EINTR)
|
||||
{
|
||||
bt_abort_msg("errno: %d", errno);
|
||||
break;
|
||||
}
|
||||
errno=0;
|
||||
clearerr(f);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (!quiet)
|
||||
bt_assert_msg(read_size == file_size, "Read %s", filename);
|
||||
|
||||
return file_body;
|
||||
}
|
||||
|
||||
static void
|
||||
bt_show_cfg_error(const struct config *cfg)
|
||||
{
|
||||
int lino = 0;
|
||||
int lino_delta = 5;
|
||||
int lino_err = cfg->err_lino;
|
||||
|
||||
const char *str = bt_load_file(cfg->err_file_name, 1);
|
||||
|
||||
while (str && *str)
|
||||
{
|
||||
lino++;
|
||||
if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
|
||||
bt_debug("%4u%s", lino, (lino_err == lino ? " >> " : " "));
|
||||
do
|
||||
{
|
||||
if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
|
||||
bt_debug("%c", *str);
|
||||
} while (*str && *(str++) != '\n');
|
||||
}
|
||||
bt_debug("\n");
|
||||
}
|
||||
|
||||
static struct config *
|
||||
bt_config_parse__(struct config *cfg)
|
||||
{
|
||||
bt_assert_msg(config_parse(cfg) == 1, "Parse %s", cfg->file_name);
|
||||
|
||||
if (cfg->err_msg)
|
||||
{
|
||||
bt_debug("Parse error %s, line %d: %s\n", cfg->err_file_name, cfg->err_lino, cfg->err_msg);
|
||||
bt_show_cfg_error(cfg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config_commit(cfg, RECONFIG_HARD, 0);
|
||||
new_config = cfg;
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
struct config *
|
||||
bt_config_parse(const char *cfg_str)
|
||||
{
|
||||
struct config *cfg = config_alloc("configuration");
|
||||
|
||||
bt_config_parse_pos = cfg_str;
|
||||
bt_config_parse_remain_len = strlen(cfg_str);
|
||||
cf_read_hook = cf_static_read;
|
||||
|
||||
return bt_config_parse__(cfg);
|
||||
}
|
||||
|
||||
struct config *
|
||||
bt_config_file_parse(const char *filepath)
|
||||
{
|
||||
struct config *cfg = config_alloc(filepath);
|
||||
|
||||
cfg->file_fd = open(filepath, O_RDONLY);
|
||||
bt_assert_msg(cfg->file_fd > 0, "Open %s", filepath);
|
||||
if (cfg->file_fd < 0)
|
||||
return NULL;
|
||||
|
||||
cf_read_hook = cf_file_read;
|
||||
|
||||
return bt_config_parse__(cfg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns @base raised to the power of @power.
|
||||
*/
|
||||
uint
|
||||
bt_naive_pow(uint base, uint power)
|
||||
{
|
||||
uint result = 1;
|
||||
uint i;
|
||||
for (i = 0; i < power; i++)
|
||||
result *= base;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* bytes_to_hex - transform data into hexadecimal representation
|
||||
* @buf: preallocated string buffer
|
||||
* @in_data: data for transformation
|
||||
* @size: the length of @in_data
|
||||
*
|
||||
* This function transforms @in_data of length @size into hexadecimal
|
||||
* representation and writes it into @buf.
|
||||
*/
|
||||
void
|
||||
bt_bytes_to_hex(char *buf, const byte *in_data, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < size; i++)
|
||||
sprintf(buf + i*2, "%02x", in_data[i]);
|
||||
}
|
||||
|
35
test/bt-utils.h
Normal file
35
test/bt-utils.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* BIRD Test -- Utils for testing parsing configuration file
|
||||
*
|
||||
* (c) 2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _BIRDTEST_UTILS_H_
|
||||
#define _BIRDTEST_UTILS_H_
|
||||
|
||||
#include "sysdep/config.h"
|
||||
|
||||
#define PRIip4 "%d.%d.%d.%d"
|
||||
#define ARGip4(x) (_I(x) >> 24) & 0xff, (_I(x) >> 16) & 0xff, (_I(x) >> 8) & 0xff, _I(x) & 0xff
|
||||
|
||||
#define PRIip6 "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X"
|
||||
#define ARGip6_HIGH(x,i) (((x).addr[(i)] >> 16) & 0xffff)
|
||||
#define ARGip6_LOW(x,i) ((x).addr[(i)] & 0xffff)
|
||||
#define ARGip6_BOTH(x,i) ARGip6_HIGH(x,i), ARGip6_LOW(x,i)
|
||||
#define ARGip6(x) ARGip6_BOTH((x), 0), ARGip6_BOTH((x), 1), ARGip6_BOTH((x), 2), ARGip6_BOTH((x), 3)
|
||||
|
||||
#define BT_CONFIG_PARSE_ROUTER_ID "router id 1.1.1.1; \n"
|
||||
#define BT_CONFIG_PARSE_STATIC_PROTO "protocol static { ipv4; } \n"
|
||||
#define BT_CONFIG_SIMPLE BT_CONFIG_PARSE_ROUTER_ID BT_CONFIG_PARSE_STATIC_PROTO
|
||||
|
||||
uint bt_naive_pow(uint base, uint power);
|
||||
void bt_bytes_to_hex(char *buf, const byte *in_data, size_t size);
|
||||
|
||||
void bt_bird_init(void);
|
||||
void bt_bird_cleanup(void);
|
||||
struct config *bt_config_parse(const char *cfg);
|
||||
struct config *bt_config_file_parse(const char *filepath);
|
||||
|
||||
#endif /* _BIRDTEST_UTILS_H_ */
|
Loading…
Reference in New Issue
Block a user