From: Florent Bruneau Date: Sun, 28 Sep 2008 20:01:20 +0000 (+0200) Subject: Start adding tests for the filters. X-Git-Url: http://git.madism.org/?p=apps%2Fpfixtools.git;a=commitdiff_plain;h=8f968cb4add434c8eaf82c0d0891d5336ba4c93e;hp=e6d0c7ab6103af206f95c1291b29c3f151a41484 Start adding tests for the filters. Signed-off-by: Florent Bruneau --- diff --git a/.gitignore b/.gitignore index 536c8be..bb16e34 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /common/tst-trie /postlicyd/postlicyd /postlicyd/tst-rbl +/postlicyd/tst-filters /pfix-srsd/pfix-srsd *.[ao] diff --git a/postlicyd/Makefile b/postlicyd/Makefile index 7901504..ac0e95a 100644 --- a/postlicyd/Makefile +++ b/postlicyd/Makefile @@ -36,7 +36,7 @@ GENERATED = policy_tokens.h policy_tokens.c \ filter_tokens.h filter_tokens.c \ hook_tokens.h hook_tokens.c \ param_tokens.h param_tokens.c -TESTS = test-rbl +TESTS = test-rbl tst-filters FILTERS = rbl.c greylist.c strlist.c match.c @@ -44,6 +44,8 @@ postlicyd_SOURCES = main-postlicyd.c ../common/lib.a filter.c config.c query.c $ postlicyd_LIBADD = $(TC_LIBS) tst-rbl_SOURCES = tst-rbl.c +tst-filters_SOURCES = tst-filters.c ../common/lib.a config.c filter.c query.c $(FILTERS) $(GENERATED) +tst-filters_LIBADD = $(TC_LIBS) hook_tokens.h hook_tokens.c: $(FILTERS) param_tokens.c param_tokens.h: $(FILTERS) config.c diff --git a/postlicyd/data/test.conf b/postlicyd/data/test.conf new file mode 100644 index 0000000..5f47d71 --- /dev/null +++ b/postlicyd/data/test.conf @@ -0,0 +1,10 @@ +filter1 { + type = match; + + condition = stress #=; + on_match = postfix:OK; + on_fail = postfix:OK; +} + + +recipient_filter = filter1; diff --git a/postlicyd/data/testcase_1 b/postlicyd/data/testcase_1 new file mode 100644 index 0000000..2541656 --- /dev/null +++ b/postlicyd/data/testcase_1 @@ -0,0 +1,26 @@ +request=smtpd_access_policy +protocol_state=RCPT +protocol_name=SMTP +helo_name=some.domain.tld +queue_id=8045F2AB23 +sender=foo@bar.tld +recipient=bar@foo.tld +recipient_count=0 +client_address=1.2.3.4 +client_name=another.domain.tld +reverse_client_name=another.domain.tld +instance=123.456.7 +sasl_method=plain +sasl_username=you +sasl_sender= +size=12345 +ccert_subject=solaris9.porcupine.org +ccert_issuer=Wietse+20Venema +ccert_fingerprint=C2:9D:F4:87:71:73:73:D9:18:E7:C2:F3:C1:DA:6E:04 +encryption_protocol=TLSv1/SSLv3 +encryption_cipher=DHE-RSA-AES256-SHA +encryption_keysize=256 +etrn_domain= +stress= + +filter1=match diff --git a/postlicyd/filter.h b/postlicyd/filter.h index 0aca7e9..1d44586 100644 --- a/postlicyd/filter.h +++ b/postlicyd/filter.h @@ -129,7 +129,7 @@ __attribute__((nonnull(1))) bool filter_build(filter_t *filter); __attribute__((nonnull(1,2))) -static inline int filter_find_with_name(A(filter_t) *array, const char *name) +static inline int filter_find_with_name(const A(filter_t) *array, const char *name) { int start = 0; int end = array->len; diff --git a/postlicyd/match.c b/postlicyd/match.c index ae4dbe4..2ec5e03 100644 --- a/postlicyd/match.c +++ b/postlicyd/match.c @@ -239,7 +239,7 @@ static inline bool match_condition(const match_condition_t *cond, const query_t break; case MATCH_EMPTY: - return !!(!!(field == NULL || *field == '\0')) ^ (!!cond->case_sensitive); + return !!((field == NULL || *field == '\0') ^ (!cond->case_sensitive)); default: assert(false && "invalid condition type"); diff --git a/postlicyd/tst-filters.c b/postlicyd/tst-filters.c new file mode 100644 index 0000000..df17397 --- /dev/null +++ b/postlicyd/tst-filters.c @@ -0,0 +1,151 @@ +/******************************************************************************/ +/* pfixtools: a collection of postfix related tools */ +/* ~~~~~~~~~ */ +/* ________________________________________________________________________ */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* */ +/* 1. Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* 2. Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* 3. The names of its contributors may not be used to endorse or promote */ +/* products derived from this software without specific prior written */ +/* permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND */ +/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE */ +/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ +/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS */ +/* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */ +/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF */ +/* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS */ +/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */ +/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ +/* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF */ +/* THE POSSIBILITY OF SUCH DAMAGE. */ +/******************************************************************************/ + +/* + * Copyright © 2008 Florent Bruneau + */ + +#include "str.h" +#include "config.h" +#include "file.h" +#include + +#define DAEMON_NAME "tst-filters" + +DECLARE_MAIN + +static bool run_testcase(const config_t *config, const char *basepath, + const char *filename) +{ + char buff[BUFSIZ]; + char path[FILENAME_MAX]; + char *end; + + snprintf(path, FILENAME_MAX, "%s%s", basepath, filename); + { + file_map_t map; + if (!file_map_open(&map, path, false)) { + return false; + } + if (map.end - map.map >= BUFSIZ) { + syslog(LOG_ERR, "File too large for a testcase: %s", path); + return false; + } + memcpy(buff, map.map, map.end - map.map); + end = buff + (map.end - map.map); + *end = '\0'; + file_map_close(&map); + } + + query_t query; + const char *eol = strstr(buff, "\n\n") + 2; + if (!query_parse(&query, buff)) { + syslog(LOG_ERR, "Cannot parse query from file %s", path); + return false; + } + + bool ok = true; + while (eol < end) { + char *neol = memchr(eol, '\n', end - eol); + if (neol == NULL) { + neol = end; + } + *neol = '\0'; + char *sep = memchr(eol, '=', neol - eol); + if (sep == NULL) { + eol = neol + 1; + syslog(LOG_ERR, "missing separator"); + continue; + } + *sep = '\0'; + + int pos = filter_find_with_name(&config->filters, eol); + if (pos == -1) { + syslog(LOG_ERR, "Unknown filter %s", eol); + eol = neol + 1; + continue; + } + ++sep; + filter_result_t result = hook_tokenize(sep, neol - sep); + if (result == HTK_UNKNOWN) { + syslog(LOG_ERR, "Unknown filter result %.*s", neol - sep, sep); + eol = neol + 1; + continue; + } + filter_t *filter = array_ptr(config->filters, pos); + + bool test = filter_test(filter, &query, result); + printf(" filter %s: %s\n", filter->name, test ? "SUCCESS" : "FAILED"); + ok = ok && test; + eol = neol + 1; + } + return ok; +} + +int main(int argc, char *argv[]) +{ + char basepath[FILENAME_MAX]; + char path[FILENAME_MAX]; + char *p; + + p = strrchr(argv[0], '/'); + if (p == NULL) { + p = argv[0]; + } else { + ++p; + } + + snprintf(basepath, FILENAME_MAX, "%.*sdata/", p - argv[0], argv[0]); + snprintf(path, FILENAME_MAX, "%s/test.conf", basepath); + + config_t *config = config_read(path); + if (config == NULL) { + return 1; + } + + DIR *dir = opendir(basepath); + if (dir == NULL) { + UNIXERR("opendir"); + return 1; + } + + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + if (strncmp("testcase_", ent->d_name, 9) == 0) { + printf("Running %s:\n", ent->d_name); + printf("%s\n", + run_testcase(config, basepath, ent->d_name) ? "SUCCESS" : "FAILED"); + } + } + closedir(dir); + + return 0; +}