Extend configured filter test suites with optional expected-error matching. Require both F_ERROR and the expected runtime log for pair and extended community constructor failures. Reset the runtime-error limiter for each expected failure so earlier tests cannot hide the message. Also cover the full 32-bit range of large community fields. Target: patch --- filter/config.Y | 24 ++++++++++---- filter/f-inst.h | 5 +-- filter/filter.c | 6 ++++ filter/filter_test.c | 42 ++++++++++++++++++++++- filter/test.conf | 79 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 10 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index c0a341c2..df894a2c 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -359,6 +359,19 @@ assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const return assert_done(setter, start, end); } +static void +add_bt_test_suite(struct symbol *sym, const char *dsc, const char *expected_error) +{ + cf_assert_symbol(sym, SYM_FUNCTION); + struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); + t->fn = sym->function; + t->fn_name = sym->name; + t->dsc = dsc; + t->expected_error = expected_error; + + add_tail(&new_config->tests, &t->n); +} + CF_DECLS CF_KEYWORDS_EXCLUSIVE(IN, FROM) @@ -453,13 +466,10 @@ custom_attr: ATTRIBUTE type symbol ';' { conf: bt_test_suite ; bt_test_suite: BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' { - cf_assert_symbol($3, SYM_FUNCTION); - struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); - t->fn = $3->function; - t->fn_name = $3->name; - t->dsc = $5; - - add_tail(&new_config->tests, &t->n); + add_bt_test_suite($3, $5, NULL); + } + | BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ',' text ')' { + add_bt_test_suite($3, $5, $7); } ; diff --git a/filter/f-inst.h b/filter/f-inst.h index 49c4eb14..5c4bd3ef 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -117,16 +117,17 @@ static inline struct f_static_attr f_new_static_attr(btype type, int code, int r struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); -/* Hook for call bt_assert() function in configuration */ +/* Bird Tests */ extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); +void f_bt_reset_runtime_error_limiter(void); -/* Bird Tests */ struct f_bt_test_suite { node n; /* Node in config->tests */ const struct f_line *fn; /* Root of function */ const struct f_line *cmp; /* Compare to this function */ const char *fn_name; /* Name of test */ const char *dsc; /* Description */ + const char *expected_error; /* Expected runtime error message */ int result; /* Desired result */ }; diff --git a/filter/filter.c b/filter/filter.c index ed056c4e..fab077fe 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -105,6 +105,12 @@ void (*bt_assert_hook)(int result, const struct f_line_item *assert); static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; +void +f_bt_reset_runtime_error_limiter(void) +{ + rl_runtime_err = (struct tbf) TBF_DEFAULT_LOG_LIMITS; +} + /** * interpret * @fs: filter state diff --git a/filter/filter_test.c b/filter/filter_test.c index 83501ba3..ce75088e 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -10,8 +10,10 @@ #define _GNU_SOURCE #endif -#include <string.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <unistd.h> #include "test/birdtest.h" #include "test/bt-utils.h" @@ -38,6 +40,41 @@ t_reconfig(const void *arg) return 1; } +static int +run_function_error(const struct f_bt_test_suite *t) +{ + FILE *capture = tmpfile(); + bt_syscall(!capture, "tmpfile"); + + int capture_fd = fileno(capture); + bt_syscall(capture_fd < 0, "fileno"); + int stderr_fd = dup(STDERR_FILENO); + bt_syscall(stderr_fd < 0, "dup"); + + bt_syscall(fflush(stderr) != 0, "fflush"); + bt_syscall(dup2(capture_fd, STDERR_FILENO) < 0, "dup2"); + f_bt_reset_runtime_error_limiter(); + enum filter_return fret = f_eval(t->fn, NULL); + bt_syscall(fflush(stderr) != 0, "fflush"); + bt_syscall(dup2(stderr_fd, STDERR_FILENO) < 0, "dup2"); + bt_syscall(close(stderr_fd) < 0, "close"); + + bt_syscall(fseek(capture, 0, SEEK_SET) != 0, "fseek"); + + char buf[1024]; + size_t len = fread(buf, 1, sizeof(buf) - 1, capture); + bt_syscall(ferror(capture), "fread"); + buf[len] = 0; + bt_syscall(fclose(capture) != 0, "fclose"); + + int result = (fret == F_ERROR) && strstr(buf, t->expected_error); + if (!result) + bt_log("Expected F_ERROR containing '%s', got %s and '%s'", + t->expected_error, filter_return_str(fret), buf); + + return result; +} + static int run_function(const void *arg) { @@ -46,6 +83,9 @@ run_function(const void *arg) if (t->cmp) return t->result == f_same(t->fn, t->cmp); + if (t->expected_error) + return run_function_error(t); + enum filter_return fret = f_eval(t->fn, NULL); return (fret < F_REJECT); diff --git a/filter/test.conf b/filter/test.conf index 3171b9e9..0b51c093 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -471,6 +471,36 @@ function t_pair() bt_test_suite(t_pair, "Testing pairs"); +function t_pair_runtime_error() +{ + int asn = 64512; + int data = 65536; + pair pp = (asn, data); +} + +bt_test_suite(t_pair_runtime_error, "Testing pair constructor runtime error", + "Pair component out of range 0..65535 (got 64512, 65536)"); + +function t_pair_boundary() +{ + int asn = 64512; + int data = 65535; + pair pp = (asn, data); + bt_assert(pp = (64512, 65535)); +} + +bt_test_suite(t_pair_boundary, "Testing pair constructor upper boundary"); + +function t_pair_runtime_error_first() +{ + int asn = 65536; + int data = 1; + pair pp = (asn, data); +} + +bt_test_suite(t_pair_runtime_error_first, "Testing pair constructor first-component runtime error", + "Pair component out of range 0..65535 (got 65536, 1)"); + @@ -1578,6 +1608,49 @@ function t_ec() bt_test_suite(t_ec, "Testing extended communities"); +function t_ec_ip_runtime_error() +{ + ip test_key = 192.0.2.1; + int test_value = 65536; + ec cc = (rt, test_key, test_value); +} + +bt_test_suite(t_ec_ip_runtime_error, + "Testing extended community IPv4-key runtime error", + "Extended community value out of range 0..65535 (IPv4 key 192.0.2.1, value 65536)"); + +function t_ec_quad_runtime_error() +{ + quad test_key = 192.0.2.1; + int test_value = 65536; + ec cc = (rt, test_key, test_value); +} + +bt_test_suite(t_ec_quad_runtime_error, + "Testing extended community quad-key runtime error", + "Extended community value out of range 0..65535 (IPv4 key 192.0.2.1, value 65536)"); + +function t_ec_asn_runtime_error() +{ + int test_key = 65536; + int test_value = 65536; + ec cc = (rt, test_key, test_value); +} + +bt_test_suite(t_ec_asn_runtime_error, + "Testing extended community 4-byte-ASN runtime error", + "Extended community value out of range 0..65535 (4-byte ASN 65536, value 65536)"); + +function t_ec_asn_boundary() +{ + int test_key = 65536; + int test_value = 65535; + ec cc = (rt, test_key, test_value); + bt_assert(cc = (rt, 65536, 65535)); +} + +bt_test_suite(t_ec_asn_boundary, "Testing extended community 4-byte-ASN upper boundary"); + @@ -1836,12 +1909,18 @@ lclist ll; lclist ll2; lclist r; { + int max_lc_value = 4294967295; + lc max_lc = (max_lc_value, max_lc_value, max_lc_value); + bt_assert(---empty--- = ---empty---); bt_assert((10, 20, 30) !~ ---empty---); bt_assert((10, 20, 30).asn = 10); bt_assert((10, 20, 30).data1 = 20); bt_assert((10, 20, 30).data2 = 30); + bt_assert(max_lc.asn = max_lc_value); + bt_assert(max_lc.data1 = max_lc_value); + bt_assert(max_lc.data2 = max_lc_value); ll = --- empty ---; ll = add(ll, (ten, 20, 30)); -- 2.47.3