From: Alan T. DeKok Date: Wed, 28 Jan 2015 16:54:35 +0000 (-0500) Subject: Added simple dynamic xlat tests X-Git-Tag: release_3_0_7~173 X-Git-Url: http://www.project-moonshot.org/gitweb/?a=commitdiff_plain;h=c053ffc0f55036f66760ab9f1c99326328e4b9de;p=freeradius.git Added simple dynamic xlat tests for stand-alone expansions --- diff --git a/Makefile b/Makefile index 9f37c07..2beeaee 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ $(BUILD_DIR)/tests/radiusd-c: raddb/test.conf ${BUILD_DIR}/bin/radiusd | build.r @echo "ok" @touch $@ -test: ${BUILD_DIR}/bin/radiusd ${BUILD_DIR}/bin/radclient tests.unit tests.keywords tests.auth tests.modules $(BUILD_DIR)/tests/radiusd-c | build.raddb +test: ${BUILD_DIR}/bin/radiusd ${BUILD_DIR}/bin/radclient tests.unit tests.xlat tests.keywords tests.auth tests.modules $(BUILD_DIR)/tests/radiusd-c | build.raddb @$(MAKE) -C src/tests tests #  Tests specifically for Travis.  We do a LOT more than just diff --git a/src/main/unittest.c b/src/main/unittest.c index d151dbf..24d2494 100644 --- a/src/main/unittest.c +++ b/src/main/unittest.c @@ -32,6 +32,8 @@ RCSID("$Id$") # include #endif +#include + /* * Global variables. */ @@ -504,6 +506,102 @@ static ssize_t xlat_poke(UNUSED void *instance, REQUEST *request, /* + * Read a file compose of xlat's and expected results + */ +static bool do_xlats(char const *filename, FILE *fp) +{ + int lineno = 0; + ssize_t len; + char *p; + char input[8192]; + char output[8192]; + REQUEST *request; + + request = request_alloc(NULL); + + request->log.lvl = debug_flag; + request->log.func = vradlog_request; + + while (fgets(input, sizeof(input), fp) != NULL) { + lineno++; + + /* + * Ignore blank lines and comments + */ + p = input; + while (isspace((int) *p)) p++; + + if (*p < ' ') continue; + if (*p == '#') continue; + + p = strchr(p, '\n'); + if (!p) { + if (!feof(fp)) { + fprintf(stderr, "Line %d too long in %s\n", + lineno, filename); + TALLOC_FREE(request); + return false; + } + } else { + *p = '\0'; + } + + /* + * Look for "xlat" + */ + if (strncmp(input, "xlat ", 5) == 0) { + ssize_t slen; + char const *error = NULL; + char *fmt = talloc_typed_strdup(NULL, input + 5); + xlat_exp_t *head; + + slen = xlat_tokenize(fmt, fmt, &head, &error); + if (slen <= 0) { + talloc_free(fmt); + snprintf(output, sizeof(output), "ERROR offset %d '%s'", (int) -slen, error); + continue; + } + + if (input[slen + 5] != '\0') { + talloc_free(fmt); + snprintf(output, sizeof(output), "ERROR offset %d 'Too much text' ::%s::", (int) slen, input + slen + 5); + continue; + } + + len = radius_xlat_struct(output, sizeof(output), request, head, NULL, NULL); + if (len < 0) { + snprintf(output, sizeof(output), "ERROR expanding xlat: %s", fr_strerror()); + continue; + } + + TALLOC_FREE(fmt); /* also frees 'head' */ + continue; + } + + /* + * Look for "data". + */ + if (strncmp(input, "data ", 5) == 0) { + if (strcmp(input + 5, output) != 0) { + fprintf(stderr, "Mismatch at line %d of %s\n\tgot : %s\n\texpected : %s\n", + lineno, filename, output, input + 5); + TALLOC_FREE(request); + return false; + } + continue; + } + + fprintf(stderr, "Unknown keyword in %s[%d]\n", filename, lineno); + TALLOC_FREE(request); + return false; + } + + TALLOC_FREE(request); + return true; +} + + +/* * The main guy. */ int main(int argc, char *argv[]) @@ -517,6 +615,7 @@ int main(int argc, char *argv[]) REQUEST *request = NULL; VALUE_PAIR *vp; VALUE_PAIR *filter_vps = NULL; + bool xlat_only = false; /* * If the server was built with debugging enabled always install @@ -558,7 +657,7 @@ int main(int argc, char *argv[]) default_log.fd = STDOUT_FILENO; /* Process the options. */ - while ((argval = getopt(argc, argv, "d:D:f:hi:mMn:o:xX")) != EOF) { + while ((argval = getopt(argc, argv, "d:D:f:hi:mMn:o:O:xX")) != EOF) { switch (argval) { case 'd': @@ -598,6 +697,15 @@ int main(int argc, char *argv[]) output_file = optarg; break; + case 'O': + if (strcmp(optarg, "xlat_only") == 0) { + xlat_only = true; + break; + } + + fprintf(stderr, "Unknown option '%s'\n", optarg); + exit(EXIT_FAILURE); + case 'X': debug_flag += 2; main_config.log_auth = true; @@ -671,6 +779,15 @@ int main(int argc, char *argv[]) } /* + * For simplicity, read xlat's. + */ + if (xlat_only) { + if (!do_xlats(input_file, fp)) rcode = EXIT_FAILURE; + if (input_file) fclose(fp); + goto finish; + } + + /* * Grab the VPs from stdin, or from the file. */ request = request_setup(fp); diff --git a/src/tests/all.mk b/src/tests/all.mk index fd7ee97..99d131a 100644 --- a/src/tests/all.mk +++ b/src/tests/all.mk @@ -1,4 +1,4 @@ -SUBMAKEFILES := rbmonkey.mk unit/all.mk keywords/all.mk auth/all.mk modules/all.mk +SUBMAKEFILES := rbmonkey.mk unit/all.mk xlat/all.mk keywords/all.mk auth/all.mk modules/all.mk # # Include all of the autoconf definitions into the Make variable space diff --git a/src/tests/keywords/all.mk b/src/tests/keywords/all.mk index 75e37b2..ab35bc2 100644 --- a/src/tests/keywords/all.mk +++ b/src/tests/keywords/all.mk @@ -116,7 +116,7 @@ TESTS.KEYWORDS_FILES := $(addprefix $(BUILD_DIR)/tests/keywords/,$(KEYWORD_FILES # tests.keywords: $(TESTS.KEYWORDS_FILES) -$(TESTS.KEYWORDS_FILES): $(TESTS.UNIT_FILES) +$(TESTS.KEYWORDS_FILES): $(TESTS.XLAT_FILES) .PHONY: clean.tests.keywords clean.tests.keywords: diff --git a/src/tests/xlat/all.mk b/src/tests/xlat/all.mk new file mode 100644 index 0000000..c76d062 --- /dev/null +++ b/src/tests/xlat/all.mk @@ -0,0 +1,58 @@ +# +# Unit tests for dynamic xlat expansions +# + +# +# The test files are files without extensions. +# The list is unordered. The order is added in the next step by looking +# at precursors. +# +XLAT_FILES := $(subst $(DIR)/,,$(wildcard $(DIR)/*.txt)) + +# +# Create the output directory +# +.PHONY: $(BUILD_DIR)/tests/xlat +$(BUILD_DIR)/tests/xlat: + @mkdir -p $@ + +# +# Files in the output dir depend on the unit tests +# +# src/tests/keywords/FOO unlang for the test +# src/tests/keywords/FOO.attrs input RADIUS and output filter +# build/tests/keywords/FOO updated if the test succeeds +# build/tests/keywords/FOO.log debug output for the test +# +# Auto-depend on modules via $(shell grep INCLUDE $(DIR)/radiusd.conf | grep mods-enabled | sed 's/.*}/raddb/')) +# +# If the test fails, then look for ERROR in the input. No error +# means it's unexpected, so we die. +# +# Otherwise, check the log file for a parse error which matches the +# ERROR line in the input. +# +$(BUILD_DIR)/tests/xlat/%: $(DIR)/% $(TESTBINDIR)/unittest | $(BUILD_DIR)/tests/xlat build.raddb + @echo XLAT-TEST $(notdir $@) + @if ! $(TESTBIN)/unittest -D share -d src/tests/xlat/ -i $< -xx -O xlat_only > $@.log 2>&1; then \ + cat $@.log; \ + echo "./$(TESTBIN)/unittest -D share -d src/tests/xlat/ -i $< -xx -O xlat_only"; \ + exit 1; \ + fi + @touch $@ + +# +# Get all of the unit test output files +# +TESTS.XLAT_FILES := $(addprefix $(BUILD_DIR)/tests/xlat/,$(XLAT_FILES)) + +# +# Depend on the output files, and create the directory first. +# +tests.xlat: $(TESTS.XLAT_FILES) + +$(TESTS.XLAT_FILES): $(TESTS.UNIT_FILES) + +.PHONY: clean.tests.xlat +clean.tests.xlat: + @rm -rf $(BUILD_DIR)/tests/xlat/ diff --git a/src/tests/xlat/expr.txt b/src/tests/xlat/expr.txt new file mode 100644 index 0000000..e2d9f10 --- /dev/null +++ b/src/tests/xlat/expr.txt @@ -0,0 +1,20 @@ +xlat %{md5:This is a string\n} +data 9ac4dbbc3c0ad2429e61d0df5dc28add + +xlat %{expr: 1 + 2 + 3 + 4} +data 10 + +xlat %{expr: 1 & ~1} +data 0 + +xlat %{expr: 2 - -1} +data 3 + +xlat %{expr: -1 * 2} +data -2 + +xlat %{expr: 1 << 2 | 1} +data 5 + +xlat %{expr: 6 + -(1 + 3)} +data 2 diff --git a/src/tests/xlat/radiusd.conf b/src/tests/xlat/radiusd.conf new file mode 100644 index 0000000..89e7f24 --- /dev/null +++ b/src/tests/xlat/radiusd.conf @@ -0,0 +1,37 @@ +# +# Minimal radiusd.conf for testing keywords +# + +raddb = raddb + +modconfdir = ${raddb}/mods-config + +correct_escapes = true + +# Only for testing! +# Setting this on a production system is a BAD IDEA. +security { + allow_vulnerable_openssl = yes +} + +modules { + $INCLUDE ${raddb}/mods-enabled/always + + $INCLUDE ${raddb}/mods-enabled/pap + + $INCLUDE ${raddb}/mods-enabled/expr +} + +server default { + authorize { + update control { + Cleartext-Password := 'hello' + } + + pap + } + + authenticate { + pap + } +}