]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Initial baseline multi-server tests for load-generator -> 5 homeserver and load-gener...
authorMarc-Andre Casavant <marc.casavant@inkbridge.io>
Mon, 23 Feb 2026 19:00:48 +0000 (14:00 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 15 Mar 2026 18:05:09 +0000 (14:05 -0400)
31 files changed:
src/tests/all.mk
src/tests/multi-server/README.md [new file with mode: 0644]
src/tests/multi-server/all.mk [new file with mode: 0644]
src/tests/multi-server/environments/configs/README.md [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/always [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/attr_filter [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/detail [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/files [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/json [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog_file [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog_socket [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/mods-available/stats [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/common/policy.d/control [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/env-setup.sh [new file with mode: 0755]
src/tests/multi-server/environments/configs/freeradius/homeserver/radiusd.conf.j2 [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/load-generator/load-generator-packets/packet.conf [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/load-generator/mods-config/files/authorize [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/load-generator/radiusd.conf.j2 [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/load-generator/stats/load-generator-client-stats.csv [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/load-generator/template.d/load-generator-templates [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/proxy/radiusd.conf.j2 [new file with mode: 0644]
src/tests/multi-server/environments/configs/freeradius/proxy/template.d/proxy-templates [new file with mode: 0644]
src/tests/multi-server/environments/docker-compose/env-1p-2hs-autoaccept.yml.j2 [new file with mode: 0644]
src/tests/multi-server/environments/docker-compose/env-5hs-autoaccept.yml.j2 [new file with mode: 0644]
src/tests/multi-server/environments/jinja-vars/env-1p-2hs-autoaccept.vars.yml [new file with mode: 0644]
src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml [new file with mode: 0644]
src/tests/multi-server/test-1p-2hs-autoaccept-5min.yml [new file with mode: 0644]
src/tests/multi-server/test-1p-2hs-autoaccept.yml [new file with mode: 0644]
src/tests/multi-server/test-5hs-autoaccept-5min.yml [new file with mode: 0644]
src/tests/multi-server/test-5hs-autoaccept.yml [new file with mode: 0644]

index c75eb39d44e28da159d158611e1e53886decc7c6..8eedaeea21f90feb2ce04e022df2f0e4d965963d 100644 (file)
@@ -102,6 +102,10 @@ endif
 $(BUILD_DIR)/tests:
        ${Q}mkdir -p $@
 
+.PHONY: test.multi-server.%
+test.multi-server.%:
+       $(MAKE) -f src/tests/multi-server/all.mk $*
+
 ######################################################################
 #
 #  Generic rules to set up the tests
diff --git a/src/tests/multi-server/README.md b/src/tests/multi-server/README.md
new file mode 100644 (file)
index 0000000..379a60b
--- /dev/null
@@ -0,0 +1,83 @@
+If you are reading this, you are probably wondering how to run a multi-server test.  Here's a quick overview.
+
+## Before You Begin
+Running the multi-server tests requires the availability of a Docker image `freeradius-build:latest` to be available on the host running the tests.
+```bash
+% cd ${FREERADIUS-SERVER-LOCAL-REPO}
+% make docker.ubuntu24.build
+% docker tag <your-freeradius-docker-image-tag> freeradius-build:latest
+```
+
+
+## Run Test With Makefile
+### Run All Tests
+
+2. Run make target based on the test name. All testcase config files start with "test-*".
+```bash
+% cd ${FREERADIUS-SERVER-LOCAL-REPO}
+% make -f src/tests/multi-server/all.mk
+```
+
+### Run Specific Tests (Example)
+```bash
+% cd ${FREERADIUS-SERVER-LOCAL-REPO}
+% make -f src/tests/multi-server/all.mk test-5hs-autoaccept
+```
+or
+```bash
+% cd ${FREERADIUS-SERVER-LOCAL-REPO}
+% make -f src/tests/multi-server/all.mk test-1p-2hs-autoaccept
+```
+
+### Optional Debug Logs and Logging Verbosity Level
+```bash
+% cd ${FREERADIUS-SERVER-LOCAL-REPO}
+% make -f src/tests/multi-server/all.mk test-5hs-autoaccept DEBUG=1 VERBOSE=4
+```
+
+## Run Multi-Server Tests Manually Without Makefile (Optional)
+
+### Clone Multi-Server Test Framework Repo & Activate Python venv
+```bash
+git clone git@github.com:InkbridgeNetworks/freeradius-multi-server.git ${FREERADIUS-MULTI-SERVER-LOCAL-REPO}
+cd ${FREERADIUS-MULTI-SERVER-LOCAL-REPO}
+./configure
+source .venv/bin/activate
+```
+
+### Render Jinja Templates
+
+In this example we render the Jinja templates used by the environment configuration used by the  `test-5hs-autoaccept` test.
+The Docker Compose `env-5hs-autoaccept.yml` file represents the `load-generator -> 5 homeserver` test environment used by the test.
+
+Render FreeRADIUS "homeserver" Virtual Server config:
+```bash
+% python3 src/config_builder.py \
+    --vars-file "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml" \
+    --aux-file "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/configs/freeradius/homeserver/radiusd.conf.j2" \
+    --include-path "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/"
+ ```
+ Render FreeRADIUS "load-generator" Virtual Server config:
+ ```bash
+ python3 src/config_builder.py \
+    --vars-file "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml" \
+    --aux-file "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/configs/freeradius/load-generator/radiusd.conf.j2" \
+    --include-path "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/"
+```
+Render Docker Compose environment:
+```bash
+ python3 src/config_builder.py \
+    --vars-file "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml" \
+    --aux-file "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/docker-compose/env-5hs-autoaccept.yml.j2" \
+    --include-path "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/"
+```
+
+### Run the test:
+```bash
+% DATA_PATH="${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/configs" \
+                       make test-framework -- -x -v \
+                       --compose "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/environments/docker-compose/env-5hs-autoaccept.yml" \
+                       --test "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/src/tests/multi-server/test-5hs-autoaccept.yml" \
+                       --use-files \
+                       --listener-dir "${FREERADIUS-MULTI-SERVER-LOCAL-REPO_ABS_PATH}/build/tests/multi-server/freeradius-multi-server-test-runtime-logs/test-5hs-autoaccept"
+```
diff --git a/src/tests/multi-server/all.mk b/src/tests/multi-server/all.mk
new file mode 100644 (file)
index 0000000..9a4ad50
--- /dev/null
@@ -0,0 +1,282 @@
+#
+# all.mk for multi-server tests
+#
+# Makefile arguments affecting test framework debug logs and verbosity:
+# - DEBUG=1 to enable debug logs from multi-server test framework
+# - VERBOSE=<level> 1 for normal verbosity (default), up to 4
+#
+
+# Set required variables for Makefile
+SHELL := /bin/bash
+
+FREERADIUS_SERVER_SRC_PATH_REL := ./
+FREERADIUS_SERVER_SRC_PATH_ABS := $(abspath $(FREERADIUS_SERVER_SRC_PATH_REL))
+FREERADIUS_SERVER_BUILD_DIR_PATH_ABS := $(FREERADIUS_SERVER_SRC_PATH_ABS)/build
+FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS := $(FREERADIUS_SERVER_SRC_PATH_ABS)/src/tests/multi-server
+FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS := $(FREERADIUS_SERVER_BUILD_DIR_PATH_ABS)/tests/multi-server
+FREERADIUS_MULTI_SERVER_FRAMEWORK_GIT_REPO := https://github.com/InkbridgeNetworks/freeradius-multi-server.git
+FREERADIUS_MULTI_SERVER_FRAMEWORK_GIT_BRANCH := logging-rework
+
+FREERADIUS_MULTI_SERVER_FRAMEWORK_LOG_DIR_ABS:= $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)/logs
+FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS := $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)/logs
+
+MULTI_SERVER_TEST_COMBINED_LOG := $(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/multi-server-tests-stdout-combined.log
+MULTI_SERVER_TEST_LINELOG_COMBINED_LOG := $(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/multi-server-tests-linelog-combined.log
+
+# Enable multi-server test framework debug logs
+DEBUG ?= 0
+DEBUG_LEVEL_0 := ""
+DEBUG_LEVEL_1 := -x
+DEBUG_LEVEL_2 := -xx
+DEBUG_ARG := $(DEBUG_LEVEL_$(DEBUG))
+
+# Multi-server test verbosity level
+VERBOSE ?= 1
+VERBOSE_LEVEL_0 := ""
+VERBOSE_LEVEL_1 := -v
+VERBOSE_LEVEL_2 := -vv
+VERBOSE_LEVEL_3 := -vvv
+VERBOSE_LEVEL_4 := -vvvv
+VERBOSE_ARG := $(VERBOSE_LEVEL_$(VERBOSE))
+
+# Default Multi-server tests (1st target of Makefile)
+# We purposely do not run all make targets here to run the short
+# tests by default.
+multi-server: test-5hs-autoaccept test-1p-2hs-autoaccept combine-multi-server-test-linelog
+
+.PHONY: test.multi-server
+test.multi-server: multi-server
+
+# Clean target to remove all .log and .txt.bak files in the runtime logs directory
+.PHONY: clean.test.multi-server
+clean.test.multi-server:
+       @echo "INFO: Removing all .log and .txt.bak files in $(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)"
+       rm -f $(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/*.log
+       rm -f $(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/*.log.bak
+       rm -f $(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/*.txt.bak
+
+# Allow standalone use: make -f src/tests/multi-server/all.mk clean
+# Prerequisite-only rule merges safely with the top-level clean target
+.PHONY: clean
+clean: clean.test.multi-server
+
+# Hook into the top-level clean.test when included as a submakefile
+clean.test: clean.test.multi-server
+
+# Additional multi-server tests for longer runs
+multi-server-5min: test-5hs-autoaccept-5min test-1p-2hs-autoaccept-5min combine-multi-server-test-linelog
+
+.PHONY: env-5hs-autoaccept test-5hs-autoaccept test-5hs-autoaccept-5min env-1p-2hs-autoaccept test-1p-2hs-autoaccept test-1p-2hs-autoaccept-5min combine-multi-server-test-linelog
+
+env-5hs-autoaccept:
+       @LOG_FILE="$(MULTI_SERVER_TEST_COMBINED_LOG)"; \
+       set -e; exec &> >(tee -a "$${LOG_FILE}"); \
+       \
+       ENV_NAME=$@; \
+       \
+       echo "INFO: FREERADIUS_SERVER_SRC_PATH_REL=$(FREERADIUS_SERVER_SRC_PATH_REL)"; \
+       echo "INFO: FREERADIUS_SERVER_SRC_PATH_ABS=$(FREERADIUS_SERVER_SRC_PATH_ABS)"; \
+       echo "INFO: FREERADIUS_SERVER_BUILD_DIR_PATH_ABS=$(FREERADIUS_SERVER_BUILD_DIR_PATH_ABS)"; \
+       echo "INFO: FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS=$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)"; \
+       echo "INFO: FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS=$(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)"; \
+       \
+       mkdir -p "$(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)"; \
+       mkdir -p "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)"; \
+       cd $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS); \
+       \
+       if [ ! -d freeradius-multi-server/.git ]; then \
+               ( git clone $(FREERADIUS_MULTI_SERVER_FRAMEWORK_GIT_REPO) freeradius-multi-server && cd freeradius-multi-server && git checkout $(FREERADIUS_MULTI_SERVER_FRAMEWORK_GIT_BRANCH) && cd freeradius-multi-server && git checkout $(FREERADIUS_MULTI_SERVER_FRAMEWORK_GIT_BRANCH) ); \
+       else \
+               #( cd freeradius-multi-server && git pull ); \
+               #( cd freeradius-multi-server ); \
+               ( cd freeradius-multi-server && git checkout $(FREERADIUS_MULTI_SERVER_FRAMEWORK_GIT_BRANCH) && git pull ); \
+       fi; \
+       \
+       cd freeradius-multi-server; \
+       $(MAKE) configure; \
+       . .venv/bin/activate; \
+       \
+       echo "INFO: Currently in $$(pwd)"; \
+       \
+       MULTI_SERVER_ENV_VARS_FILE_PATH_ABS="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/jinja-vars/$$ENV_NAME.vars.yml"; \
+       JINJA_RENDERING_SCOPE_PATH_ABS="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)"; \
+       echo "INFO: MULTI_SERVER_ENV_VARS_FILE_PATH_ABS=$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS"; \
+       echo "INFO: FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS=$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)"; \
+       echo "INFO: JINJA_RENDERING_SCOPE_PATH_ABS=$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+       \
+       set -x; \
+       \
+       python3 src/config_builder.py \
+       --vars-file "$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS" \
+       --aux-file "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs/freeradius/homeserver/radiusd.conf.j2" \
+       --include-path "$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+       \
+       python3 src/config_builder.py \
+       --vars-file "$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS" \
+       --aux-file "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs/freeradius/load-generator/radiusd.conf.j2" \
+       --include-path "$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+       \
+       python3 src/config_builder.py \
+       --vars-file "$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS" \
+       --aux-file "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/docker-compose/$$ENV_NAME.yml.j2" \
+       --include-path "$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+
+
+test-5hs-autoaccept: env-5hs-autoaccept
+       @LOG_FILE="$(MULTI_SERVER_TEST_COMBINED_LOG)"; \
+       set -e; exec &> >(tee -a "$${LOG_FILE}"); \
+       \
+       TEST_NAME=$@; \
+       \
+       cd $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)/freeradius-multi-server; \
+       . .venv/bin/activate; \
+       \
+       echo "INFO: Running $${TEST_NAME}"; \
+       \
+       set -x; \
+       \
+       DATA_PATH="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs" \
+       make test-framework \
+               -- $(DEBUG_ARG) $(VERBOSE_ARG) \
+               --compose "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/docker-compose/env-5hs-autoaccept.yml" \
+               --test "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/$$TEST_NAME.yml" \
+               --use-files \
+               --listener-dir "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)" \
+               --log-dir "$(FREERADIUS_MULTI_SERVER_FRAMEWORK_LOG_DIR_ABS)" \
+               --output "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/$$TEST_NAME-result.log"
+
+test-5hs-autoaccept-5min: env-5hs-autoaccept
+       @LOG_FILE="$(MULTI_SERVER_TEST_COMBINED_LOG)"; \
+       set -e; exec &> >(tee -a "$${LOG_FILE}"); \
+       \
+       TEST_NAME=$@; \
+       \
+       cd $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)/freeradius-multi-server; \
+       . .venv/bin/activate; \
+       \
+       echo "INFO: Running $${TEST_NAME}"; \
+       \
+       set -x; \
+       \
+       DATA_PATH="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs" \
+       make test-framework \
+               -- $(DEBUG_ARG) $(VERBOSE_ARG) \
+               --compose "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/docker-compose/env-5hs-autoaccept.yml" \
+               --test "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/test-5hs-autoaccept-5min.yml" \
+               --use-files \
+               --listener-dir "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)" \
+               --log-dir "$(FREERADIUS_MULTI_SERVER_FRAMEWORK_LOG_DIR_ABS)" \
+               --output "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/$$TEST_NAME-result.log"
+
+env-1p-2hs-autoaccept:
+       @LOG_FILE="$(MULTI_SERVER_TEST_COMBINED_LOG)"; \
+       set -e; exec &> >(tee -a "$${LOG_FILE}"); \
+       \
+       ENV_NAME=$@; \
+       \
+       echo "INFO: FREERADIUS_SERVER_SRC_PATH_REL=$(FREERADIUS_SERVER_SRC_PATH_REL)"; \
+       echo "INFO: FREERADIUS_SERVER_SRC_PATH_ABS=$(FREERADIUS_SERVER_SRC_PATH_ABS)"; \
+       echo "INFO: FREERADIUS_SERVER_BUILD_DIR_PATH_ABS=$(FREERADIUS_SERVER_BUILD_DIR_PATH_ABS)"; \
+       echo "INFO: FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS=$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)"; \
+       echo "INFO: FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS=$(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)"; \
+       \
+       mkdir -p "$(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)"; \
+       mkdir -p "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)"; \
+       cd $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS); \
+       \
+       if [ ! -d freeradius-multi-server/.git ]; then \
+               git clone $(FREERADIUS_MULTI_SERVER_FRAMEWORK_GIT_REPO); \
+       else \
+               #( cd freeradius-multi-server && git pull ); \
+               ( cd freeradius-multi-server ); \
+       fi; \
+       \
+       cd freeradius-multi-server; \
+       $(MAKE) configure; \
+       . .venv/bin/activate; \
+       \
+       echo "INFO: Currently in $$(pwd)"; \
+       \
+       MULTI_SERVER_ENV_VARS_FILE_PATH_ABS="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/jinja-vars/$$ENV_NAME.vars.yml"; \
+       JINJA_RENDERING_SCOPE_PATH_ABS="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)"; \
+       echo "INFO: MULTI_SERVER_ENV_VARS_FILE_PATH_ABS=$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS"; \
+       echo "INFO: FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS=$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)"; \
+       echo "INFO: JINJA_RENDERING_SCOPE_PATH_ABS=$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+       \
+       set -x; \
+       \
+       python3 src/config_builder.py \
+       --vars-file "$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS" \
+       --aux-file "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs/freeradius/homeserver/radiusd.conf.j2" \
+       --include-path "$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+       \
+       python3 src/config_builder.py \
+       --vars-file "$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS" \
+       --aux-file "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs/freeradius/proxy/radiusd.conf.j2" \
+       --include-path "$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+       \
+       python3 src/config_builder.py \
+       --vars-file "$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS" \
+       --aux-file "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs/freeradius/load-generator/radiusd.conf.j2" \
+       --include-path "$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+       \
+       python3 src/config_builder.py \
+       --vars-file "$$MULTI_SERVER_ENV_VARS_FILE_PATH_ABS" \
+       --aux-file "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/docker-compose/$$ENV_NAME.yml.j2" \
+       --include-path "$$JINJA_RENDERING_SCOPE_PATH_ABS"; \
+
+
+test-1p-2hs-autoaccept: env-1p-2hs-autoaccept
+       @LOG_FILE="$(MULTI_SERVER_TEST_COMBINED_LOG)"; \
+       set -e; exec &> >(tee -a "$${LOG_FILE}"); \
+       \
+       TEST_NAME=$@; \
+       \
+       cd $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)/freeradius-multi-server; \
+       . .venv/bin/activate; \
+       \
+       echo "INFO: Running $${TEST_NAME}"; \
+       \
+       set -x; \
+       \
+       DATA_PATH="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs" \
+       make test-framework \
+               -- $(DEBUG_ARG) $(VERBOSE_ARG) \
+               --compose "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/docker-compose/env-1p-2hs-autoaccept.yml" \
+               --test "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/test-1p-2hs-autoaccept.yml" \
+               --use-files \
+               --listener-dir "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)" \
+               --log-dir "$(FREERADIUS_MULTI_SERVER_FRAMEWORK_LOG_DIR_ABS)" \
+               --output "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/$$TEST_NAME-result.log"
+
+test-1p-2hs-autoaccept-5min: env-1p-2hs-autoaccept
+       @LOG_FILE="$(MULTI_SERVER_TEST_COMBINED_LOG)"; \
+       set -e; exec &> >(tee -a "$${LOG_FILE}"); \
+       \
+       TEST_NAME=$@; \
+       \
+       cd $(FREERADIUS_MULTI_SERVER_BUILD_DIR_PATH_ABS)/freeradius-multi-server; \
+       . .venv/bin/activate; \
+       \
+       echo "INFO: Running $${TEST_NAME}"; \
+       \
+       set -x; \
+       \
+       DATA_PATH="$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/configs" \
+       make test-framework \
+               -- $(DEBUG_ARG) $(VERBOSE_ARG) \
+               --compose "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/environments/docker-compose/env-1p-2hs-autoaccept.yml" \
+               --test "$(FREERADIUS_MULTI_SERVER_TESTS_BASE_PATH_ABS)/$$TEST_NAME.yml" \
+               --use-files \
+               --listener-dir "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)" \
+               --log-dir "$(FREERADIUS_MULTI_SERVER_FRAMEWORK_LOG_DIR_ABS)" \
+               --output "$(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/$$TEST_NAME-result.log"
+
+combine-multi-server-test-linelog:
+       @echo "INFO: Combining multi-server test linelog message output into $(MULTI_SERVER_TEST_LINELOG_COMBINED_LOG)"
+       @rm -f $(MULTI_SERVER_TEST_LINELOG_COMBINED_LOG)
+       for f in $(FREERADIUS_MULTI_SERVER_TEST_RUNTIME_LOGS_DIR_ABS)/*.txt.bak; do \
+         echo "$$f"; \
+         cat "$$f"; \
+         echo ""; \
+       done > $(MULTI_SERVER_TEST_LINELOG_COMBINED_LOG)
diff --git a/src/tests/multi-server/environments/configs/README.md b/src/tests/multi-server/environments/configs/README.md
new file mode 100644 (file)
index 0000000..7cbfa82
--- /dev/null
@@ -0,0 +1,2 @@
+Test environment configuration files which includes, and not limited to, FreeRADIUS configuration, and 3rd party
+environment component configuration, etc.
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/always b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/always
new file mode 100644 (file)
index 0000000..18bbcb4
--- /dev/null
@@ -0,0 +1,7 @@
+
+always ok {
+       rcode = ok
+}
+always handled {
+       rcode = handled
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/attr_filter b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/attr_filter
new file mode 100644 (file)
index 0000000..321ac61
--- /dev/null
@@ -0,0 +1,15 @@
+
+attr_filter attr_filter.access_reject {
+       key = User-Name
+       filename = ${modconfdir}/${.:name}/access_reject
+}
+
+attr_filter attr_filter.access_challenge {
+       key = User-Name
+       filename = ${modconfdir}/${.:name}/access_challenge
+}
+
+attr_filter attr_filter.accounting_response {
+       key = User-Name
+       filename = ${modconfdir}/${.:name}/accounting_response
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/detail b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/detail
new file mode 100644 (file)
index 0000000..68e7fe7
--- /dev/null
@@ -0,0 +1,7 @@
+
+detail {
+        filename = "${radacctdir}/%{Net.Src.IP}/detail-%Y-%m-%d"
+        escape_filenames = no
+        permissions = 0600
+        header = "%t"
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/files b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/files
new file mode 100644 (file)
index 0000000..1bf5ba0
--- /dev/null
@@ -0,0 +1,9 @@
+
+files {
+       moddir = ${modconfdir}/${.:instance}
+       filename = ${moddir}/authorize
+}
+
+files files_accounting {
+       filename = ${modconfdir}/files/accounting
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/json b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/json
new file mode 100644 (file)
index 0000000..f6693ab
--- /dev/null
@@ -0,0 +1,8 @@
+json {
+       encode {
+               output_mode = object_simple
+               value {
+                       binary_format = base16
+               }
+       }
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog
new file mode 100644 (file)
index 0000000..3e89bda
--- /dev/null
@@ -0,0 +1,20 @@
+
+linelog {
+       format = "This is a log message for %{User-Name}"
+       destination = file
+
+       file {
+               filename = ${logdir}/linelog
+               permissions = 0600
+               escape_filenames = no
+
+               # Disable message buffering
+               buffer_count = 0
+               buffer_delay = 0
+               buffer_expiry = 0
+       }
+}
+
+linelog log_stdout {
+       destination = stdout
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog_file b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog_file
new file mode 100644 (file)
index 0000000..3d92e08
--- /dev/null
@@ -0,0 +1,15 @@
+
+linelog linelog_test_framework {
+        destination = file
+
+        file {
+                filename = /var/run/multi-server/$ENV{TEST_PROJECT_NAME}.txt
+                permissions = 0644
+                escape_filenames = no
+
+                # Disable message buffering
+               buffer_count = 0
+               buffer_delay = 0
+               buffer_expiry = 0
+        }
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog_socket b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/linelog_socket
new file mode 100644 (file)
index 0000000..9a21132
--- /dev/null
@@ -0,0 +1,19 @@
+
+linelog linelog_test_framework {
+        destination = unix
+        format = "bar"
+
+        unix {
+                filename = /var/run/multi-server/$ENV{TEST_PROJECT_NAME}.sock
+                pool {
+                        start = 1
+                        min = 1
+                        max = 1
+                        spare = 0
+                        uses = 0
+                        retry_delay = 30
+                        lifetime = 0
+                        idle_timeout = 0
+                }
+        }
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/mods-available/stats b/src/tests/multi-server/environments/configs/freeradius/common/mods-available/stats
new file mode 100644 (file)
index 0000000..1114816
--- /dev/null
@@ -0,0 +1,4 @@
+
+stats {
+
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/common/policy.d/control b/src/tests/multi-server/environments/configs/freeradius/common/policy.d/control
new file mode 100644 (file)
index 0000000..c2f3893
--- /dev/null
@@ -0,0 +1,6 @@
+
+accept {
+        reply.Packet-Type := ::Access-Accept
+
+        handled
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/env-setup.sh b/src/tests/multi-server/environments/configs/freeradius/env-setup.sh
new file mode 100755 (executable)
index 0000000..ff46e3a
--- /dev/null
@@ -0,0 +1,7 @@
+apt-get update
+apt-get install -y iputils-ping iproute2 ipcalc
+IP_CIDR=$(ip -o -f inet addr show eth0 | awk '{print $4}')
+TEST_SUBNET=$(ipcalc -n "$IP_CIDR" | grep Network | awk '{print $2}')
+export TEST_SUBNET
+echo "TEST_SUBNET=$TEST_SUBNET" >> /etc/environment
+echo "Detected TEST_SUBNET: $TEST_SUBNET"
diff --git a/src/tests/multi-server/environments/configs/freeradius/homeserver/radiusd.conf.j2 b/src/tests/multi-server/environments/configs/freeradius/homeserver/radiusd.conf.j2
new file mode 100644 (file)
index 0000000..ba1fc76
--- /dev/null
@@ -0,0 +1,231 @@
+name        = homeserver
+
+raddbdir    = /etc/freeradius
+confdir     = ${raddbdir}
+modconfdir  = ${confdir}/mods-config
+logdir      = /var/log/freeradius
+radacctdir  = ${logdir}/radacct
+
+security {
+        allow_core_dumps = yes
+}
+
+trigger {
+
+       server {
+               start = "%linelog('server_start homeserver starting')"
+
+               stop = "%linelog('server_stop homeserver stopping')"
+
+               max_requests = "%linelog('server_max_requests homeserver max requests reached')"
+       }
+
+}
+
+# logging configuration required for linelog module
+log {
+       destination = files
+       file = ${logdir}/radius.log
+       syslog_facility = daemon
+       stripped_names = no
+       auth = yes
+       auth_badpass = yes
+       auth_goodpass = yes
+}
+
+modules {
+       # Common linelog module configuration
+       {% include "environments/configs/freeradius/common/mods-available/linelog" %}
+
+       # Test framework linelog module configuration based on OS environment
+       {% if listener_type == "unix" %}
+        {% include "environments/configs/freeradius/common/mods-available/linelog_socket" %}
+       {% elif listener_type == "file" %}
+        {% include "environments/configs/freeradius/common/mods-available/linelog_file" %}
+       {% endif %}
+
+       # Common json module configuration
+       {% include "environments/configs/freeradius/common/mods-available/json" %}
+
+       # Common always module configuration
+       {% include "environments/configs/freeradius/common/mods-available/always" %}
+
+       # Common attr_filter module configuration
+       {% include "environments/configs/freeradius/common/mods-available/attr_filter" %}
+
+       # Common files module configuration
+       {% include "environments/configs/freeradius/common/mods-available/files" %}
+
+       # Common detail module configuration
+       {% include "environments/configs/freeradius/common/mods-available/detail" %}
+}
+
+policy {
+       # Common control policy configuration
+       {% include "environments/configs/freeradius/common/policy.d/control" %}
+}
+
+server hs-auto-accept {
+
+       namespace = radius
+
+       listen authentication {
+               type = Access-Request
+               type = Status-Server
+               transport = udp
+               require_message_authenticator = auto
+               limit_proxy_state = auto
+               limit {
+                       max_clients = 256
+                       max_connections = 256
+                       idle_timeout = 60.0
+                       dynamic_timeout = 600.0
+                       nak_lifetime = 30.0
+                       cleanup_delay = 5.0
+               }
+               udp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+               tcp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+       }
+
+       listen authentication {
+               type = Access-Request
+               type = Status-Server
+               transport = tcp
+               tcp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+       }
+
+       listen accounting {
+               type = Accounting-Request
+               transport = udp
+               udp {
+                       ipaddr = *
+                       port = 1813
+               }
+       }
+
+       client upstream-proxy {
+               ipaddr = $ENV{TEST_SUBNET}
+               secret = testing123
+               require_message_authenticator = auto
+               limit_proxy_state = auto
+       }
+
+       recv Access-Request {
+               string Log-Timestamp
+               string Log-Label
+               string Log-Message
+               string Log-Homeserver-IP-Port
+               string Log-Request-Source-IP-Port
+
+               # Initialization
+               Log-Timestamp := "%Y-%m-%d-%H:%G:%e"
+               Log-Label := "INFO"
+               Log-Message := "Access-Request received"
+               Log-Homeserver-IP-Port := "%{Net.Dst.IP}:%{Net.Dst.Port}"
+               Log-Request-Source-IP-Port := "%{Net.Src.IP}:%{Net.Src.Port}"
+
+               {% raw %}
+               %linelog("homeserver-access-request {\"Log-Timestamp\": %{Log-Timestamp}, \"Log-Label\": %{Log-Label}, \"Log-Message\": %{Log-Message}, \"Log-Homeserver-IP-Port\": %{Log-Homeserver-IP-Port}, \"Log-Request-Source-IP-Port\": %{Log-Request-Source-IP-Port}}, \"User-Name\": \"%{%{User-Name}}\", \"Calling-Station-Id\": \"%{Calling-Station-Id}\"")
+
+               {% endraw %}
+               accept
+       }
+
+       send Access-Accept {
+               string Log-Timestamp
+               string Log-Label
+               string Log-Message
+               string Log-Homeserver-IP-Port
+               string Log-Request-Source-IP-Port
+
+               # Initialization
+               Log-Timestamp := "%Y-%m-%d-%H:%G:%e"
+               Log-Label := "INFO"
+               Log-Message := "Access-Accept sent"
+               Log-Homeserver-IP-Port := "%{Net.Dst.IP}:%{Net.Dst.Port}"
+               Log-Request-Source-IP-Port := "%{Net.Src.IP}:%{Net.Src.Port}"
+
+               {% raw %}
+               %linelog("homeserver-access-accept {\"Log-Timestamp\": %{Log-Timestamp}, \"Log-Label\": %{Log-Label}, \"Log-Message\": %{Log-Message}, \"Log-Homeserver-IP-Port\": %{Log-Homeserver-IP-Port}, \"Log-Request-Source-IP-Port\": %{Log-Request-Source-IP-Port}}")
+               {% endraw %}
+
+               handled
+       }
+
+       recv Status-Server {
+               ok
+       }
+
+       send Access-Challenge {
+               attr_filter.access_challenge
+       }
+
+       send Access-Reject {
+               string Log-Timestamp
+               string Log-Label
+               string Log-Message
+               string Log-Homeserver-IP-Port
+               string Log-Request-Source-IP-Port
+
+               # Initialization
+               Log-Timestamp := "%Y-%m-%d-%H:%G:%e"
+               Log-Label := "ERROR"
+               Log-Message := "Access-Reject sent"
+               Log-Homeserver-IP-Port := "%{Net.Dst.IP}:%{Net.Dst.Port}"
+               Log-Request-Source-IP-Port := "%{Net.Src.IP}:%{Net.Src.Port}"
+
+               {% raw %}
+               %linelog_test_framework("homeserver-access-reject {\"Log-Timestamp\": %{Log-Timestamp}, \"Log-Label\": %{Log-Label}, \"Log-Message\": %{Log-Message}, \"Log-Homeserver-IP-Port\": %{Log-Homeserver-IP-Port}, \"Log-Request-Source-IP-Port\": %{Log-Request-Source-IP-Port}}")
+               {% endraw %}
+
+               attr_filter.access_reject
+       }
+
+       recv Accounting-Request {
+               files_accounting
+       }
+
+       accounting Start {
+       }
+
+       accounting Stop {
+       }
+
+       accounting Interim-Update {
+       }
+
+       accounting Accounting-On {
+       }
+
+       accounting Accounting-Off {
+       }
+
+       accounting Failed {
+       }
+
+       send Accounting-Response {
+               detail
+               attr_filter.accounting_response
+       }
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/load-generator/load-generator-packets/packet.conf b/src/tests/multi-server/environments/configs/freeradius/load-generator/load-generator-packets/packet.conf
new file mode 100644 (file)
index 0000000..46c2a8f
--- /dev/null
@@ -0,0 +1,3 @@
+User-Name       = "testuser"
+User-Password   = "testpass"
+Calling-Station-ID = "F1-F2-F3-F4-F5-F6"
diff --git a/src/tests/multi-server/environments/configs/freeradius/load-generator/mods-config/files/authorize b/src/tests/multi-server/environments/configs/freeradius/load-generator/mods-config/files/authorize
new file mode 100644 (file)
index 0000000..eba3cb9
--- /dev/null
@@ -0,0 +1 @@
+testuser Password.Cleartext := "testpass"
diff --git a/src/tests/multi-server/environments/configs/freeradius/load-generator/radiusd.conf.j2 b/src/tests/multi-server/environments/configs/freeradius/load-generator/radiusd.conf.j2
new file mode 100644 (file)
index 0000000..052bb37
--- /dev/null
@@ -0,0 +1,223 @@
+name       = load-generator
+
+raddbdir   = /etc/freeradius
+confdir    = ${raddbdir}
+modconfdir = ${confdir}/mods-config
+logdir     = /var/log/freeradius
+radacctdir = ${logdir}/radacct
+
+templates {
+       {% include "environments/configs/freeradius/load-generator/template.d/load-generator-templates" %}
+}
+
+security {
+       allow_core_dumps = yes
+}
+
+# logging configuration required for linelog module
+log {
+       destination = files
+       file = ${logdir}/radius.log
+       syslog_facility = daemon
+       stripped_names = no
+       auth = yes
+       auth_badpass = yes
+       auth_goodpass = yes
+}
+
+modules {
+       # Common linelog module configuration
+       {% include "environments/configs/freeradius/common/mods-available/linelog" %}
+
+       # Test framework linelog module configuration based on OS environment
+       {% if listener_type == "unix" %}
+        {% include "environments/configs/freeradius/common/mods-available/linelog_socket" %}
+       {% elif listener_type == "file" %}
+        {% include "environments/configs/freeradius/common/mods-available/linelog_file" %}
+       {% endif %}
+
+       # Common json module configuration
+       {% include "environments/configs/freeradius/common/mods-available/json" %}
+
+       # Common stats module configuration
+       {% include "environments/configs/freeradius/common/mods-available/stats" %}
+
+       # radius module instance configuration
+       {% for i in range(1, (load_gen_num_of_dst_servers + 1)) %}
+       radius radius-module-dst-server{{ i }} {
+               $template radius-module-dst-server-tmpl
+               udp {
+                       ipaddr = {{ load_gen_dst_server_name }}{{ i }}
+               }
+       }
+       {% endfor %}
+
+}
+
+server load-generator {
+
+       namespace = radius
+
+       listen load {
+               handler = load
+               type = Access-Request
+               transport = step
+
+               step {
+
+                       # Default packet config to use by the load-generator
+                       filename = ${confdir}/load-generator-packets/packet.conf
+
+                       csv = ${confdir}/stats/load-generator-client-stats.csv
+
+                       max_attributes = 64
+
+                       #
+                       # The load profile is configured via environment variables set
+                       # in the testcase configuration files.
+                       #
+                       start_pps = $ENV{TEST_CONF_START_PPS}
+                       max_pps   = $ENV{TEST_CONF_MAX_PPS}
+                       duration  = $ENV{TEST_CONF_DURATION}
+                       step = $ENV{TEST_CONF_STEP}
+                       max_backlog = $ENV{TEST_CONF_MAX_BACKLOG}
+                       parallel = $ENV{TEST_CONF_PARALLEL}
+                       num_messages = $ENV{TEST_CONF_NUM_MESSAGES}
+                       repeat = no
+               }
+       }
+
+       listen authentication {
+               type = Access-Request
+               type = Status-Server
+               transport = udp
+               require_message_authenticator = auto
+               limit_proxy_state = auto
+
+               limit {
+                       max_clients = 256
+                       max_connections = 256
+                       idle_timeout = 60.0
+                       dynamic_timeout = 600.0
+                       nak_lifetime = 30.0
+                       cleanup_delay = 5.0
+               }
+
+               udp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+
+               tcp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+       }
+
+       listen authentication {
+               type = Access-Request
+               type = Status-Server
+               transport = tcp
+
+               tcp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+       }
+
+       client localhost {
+               shortname = client-localhost
+               ipaddr = *
+               secret = testing123
+       }
+
+       listen statusserver {
+               transport = udp
+               udp {
+                       ipaddr = *
+                       port = 1820
+               }
+
+               type = Status-Server
+       }
+
+       #
+       #  Receive a Status-Server packet
+       #
+       recv Status-Server {
+               uint32 Status-Server-Counter
+               uint32 Access-Request-Counter
+               uint32 Access-Accept-Counter
+               uint32 Access-Reject-Counter
+               string Status-Server-Result
+               string Status-Server-Message
+
+               # Initialization
+               Status-Server-Counter := 0
+               Access-Request-Counter := 0
+               Access-Accept-Counter := 0
+               Access-Reject-Counter := 0
+               Status-Server-Result := "FAIL"
+               Status-Server-Message := ""
+
+               # stats module required to have access to the Status-Server's global statistics
+               stats
+
+               {%raw%}
+               Status-Server-Counter := %{reply.FreeRADIUS.Stats4.Packet-Counters.Status-Server || 0}
+               Access-Request-Counter := %{reply.FreeRADIUS.Stats4.Packet-Counters.Access-Request || 0}
+               Access-Accept-Counter := %{reply.FreeRADIUS.Stats4.Packet-Counters.Access-Accept || 0}
+               Access-Reject-Counter := %{reply.FreeRADIUS.Stats4.Packet-Counters.Access-Reject || 0}
+
+               # The Stats Module documentation explicitly states: "When listed in a recv Status-Server section, it will add global server statistics to the packet,
+               # hence the reason "reply.FreeRADIUS.Stats4" is used below.
+               if ((reply.FreeRADIUS.Stats4.Packet-Counters.Access-Accept - reply.FreeRADIUS.Stats4.Packet-Counters.Status-Server) != reply.FreeRADIUS.Stats4.Packet-Counters.Access-Request) {
+                       Status-Server-Result := "FAIL"
+                       Status-Server-Message := "expected vs actual stat mismatch"
+               }
+
+               if (reply.FreeRADIUS.Stats4.Packet-Counters.Access-Request == (reply.FreeRADIUS.Stats4.Packet-Counters.Access-Accept - reply.FreeRADIUS.Stats4.Packet-Counters.Status-Server)) {
+                       Status-Server-Result := "PASS"
+                       Status-Server-Message := "requests processed successfully"
+               }
+
+               %linelog_test_framework("load-generator-status-server {\"Status-Server-Result\": %json.quote(%{Status-Server-Result}), \"Status-Server-Message\": %json.quote(%{Status-Server-Message}), \"Status-Server-Counter\": %{Status-Server-Counter}, \"Access-Request-Counter\": %{Access-Request-Counter}, \"Access-Accept-Counter\": %{Access-Accept-Counter}, \"Access-Reject-Counter\": %{Access-Reject-Counter}}")
+
+               {%endraw%}
+       }
+
+       recv Access-Request {
+               # Use the load-generator-proxy authenticate logic
+               control.Auth-Type := "load-generator-proxy"
+       }
+
+       authenticate load-generator-proxy {
+               # Use redundant-load-balance to distribute requests to multiple home servers
+               redundant-load-balance {
+                       {% for i in range(1, (load_gen_num_of_dst_servers + 1)) %}
+                       radius-module-dst-server{{ i }}
+                       {% endfor %}
+               }
+       }
+
+       send Access-Accept {
+               stats
+       }
+
+       send Access-Reject {
+               stats
+       }
+
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/load-generator/stats/load-generator-client-stats.csv b/src/tests/multi-server/environments/configs/freeradius/load-generator/stats/load-generator-client-stats.csv
new file mode 100644 (file)
index 0000000..34c1880
--- /dev/null
@@ -0,0 +1 @@
+"time","last_packet","rtt","rttvar","pps","pps_accepted","sent","received","backlog","max_backlog","<usec","us","10us","100us","ms","10ms","100ms","s","blocked"
diff --git a/src/tests/multi-server/environments/configs/freeradius/load-generator/template.d/load-generator-templates b/src/tests/multi-server/environments/configs/freeradius/load-generator/template.d/load-generator-templates
new file mode 100644 (file)
index 0000000..71e80d6
--- /dev/null
@@ -0,0 +1,17 @@
+
+#
+# radius module template for load-generator
+#
+radius-module-dst-server-tmpl {
+       mode = client
+       transport = udp
+       type = Access-Request
+       require_message_authenticator = auto
+       file {
+            filename = ${logdir}/packets.bin
+       }
+       udp {
+               port = 1812
+               secret = testing123
+       }
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/proxy/radiusd.conf.j2 b/src/tests/multi-server/environments/configs/freeradius/proxy/radiusd.conf.j2
new file mode 100644 (file)
index 0000000..a64911d
--- /dev/null
@@ -0,0 +1,141 @@
+name        = proxy
+
+raddbdir    = /etc/freeradius
+confdir     = ${raddbdir}
+modconfdir  = ${confdir}/mods-config
+logdir      = /var/log/freeradius
+radacctdir  = ${logdir}/radacct
+
+templates {
+       {% include "environments/configs/freeradius/proxy/template.d/proxy-templates" %}
+}
+
+security {
+        allow_core_dumps = yes
+}
+
+# logging configuration required for linelog module
+log {
+       destination = files
+       file = ${logdir}/radius.log
+       syslog_facility = daemon
+       stripped_names = no
+       auth = yes
+       auth_badpass = yes
+       auth_goodpass = yes
+}
+
+modules {
+       # Common linelog module configuration
+       {% include "environments/configs/freeradius/common/mods-available/linelog" %}
+
+       # Test framework linelog module configuration based on OS environment
+       {% if listener_type == "unix" %}
+        {% include "environments/configs/freeradius/common/mods-available/linelog_socket" %}
+       {% elif listener_type == "file" %}
+        {% include "environments/configs/freeradius/common/mods-available/linelog_file" %}
+       {% endif %}
+
+       # Common json module configuration
+       {% include "environments/configs/freeradius/common/mods-available/json" %}
+
+       # Common always module configuration
+       {% include "environments/configs/freeradius/common/mods-available/always" %}
+
+       # radius module instance configuration
+       {% for i in range(1, (proxy_num_of_dst_servers + 1)) %}
+       radius radius-module-dst-server{{ i }} {
+               $template radius-module-dst-server-tmpl
+               udp {
+                       ipaddr = {{ proxy_dst_server_name }}{{ i }}
+               }
+       }
+       {% endfor %}
+
+}
+
+policy {
+       # Common control policy configuration
+       {% include "environments/configs/freeradius/common/policy.d/control" %}
+}
+
+server proxy {
+
+       namespace = radius
+
+       listen authentication {
+               type = Access-Request
+               type = Status-Server
+               transport = udp
+               require_message_authenticator = auto
+               limit_proxy_state = auto
+
+               limit {
+                       max_clients = 256
+                       max_connections = 256
+                       idle_timeout = 60.0
+                       dynamic_timeout = 600.0
+                       nak_lifetime = 30.0
+                       cleanup_delay = 5.0
+               }
+
+               udp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+
+               tcp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+       }
+
+       listen authentication {
+               type = Access-Request
+               type = Status-Server
+               transport = tcp
+
+               tcp {
+                       ipaddr = *
+                       port = 1812
+                       networks {
+                               allow = 127/8
+                               allow = 192.0.2/24
+                       }
+               }
+       }
+
+       client upstream-proxy {
+               ipaddr = $ENV{TEST_SUBNET}
+               secret = testing123
+               require_message_authenticator = auto
+               limit_proxy_state = auto
+       }
+
+       recv Access-Request {
+               # Use the load-generator-proxy authenticate logic
+               control.Auth-Type := "redundant-load-balance-proxy"
+       }
+
+       authenticate redundant-load-balance-proxy {
+               # Use redundant-load-balance to distribute requests to multiple home servers
+               redundant-load-balance {
+                       {% for i in range(1, (proxy_num_of_dst_servers + 1)) %}
+                       radius-module-dst-server{{ i }}
+                       {% endfor %}
+               }
+       }
+
+       recv Status-Server {
+               ok
+       }
+
+}
diff --git a/src/tests/multi-server/environments/configs/freeradius/proxy/template.d/proxy-templates b/src/tests/multi-server/environments/configs/freeradius/proxy/template.d/proxy-templates
new file mode 100644 (file)
index 0000000..1419600
--- /dev/null
@@ -0,0 +1,17 @@
+
+#
+# radius module template for load-generator
+#
+radius-module-dst-server-tmpl {
+       mode = proxy
+       transport = udp
+       type = Access-Request
+       require_message_authenticator = auto
+       file {
+            filename = ${logdir}/packets.bin
+       }
+       udp {
+               port = 1812
+               secret = testing123
+       }
+}
diff --git a/src/tests/multi-server/environments/docker-compose/env-1p-2hs-autoaccept.yml.j2 b/src/tests/multi-server/environments/docker-compose/env-1p-2hs-autoaccept.yml.j2
new file mode 100644 (file)
index 0000000..b135e72
--- /dev/null
@@ -0,0 +1,108 @@
+# ---------------------------------------------------------------
+# Docker Compose Test Environment:
+#
+#                             --> HS1 (auto-accept)
+#   load-generator --> Proxy1
+#                             --> HS2 (auto-accept)
+#
+# ---------------------------------------------------------------
+x-common-config: &id001
+  cap_add:
+  - NET_ADMIN
+  - SYS_PTRACE
+services:
+{% for i in range(1, (compose_num_of_home_servers + 1)) %}
+  homeserver{{ i }}:
+    image: freeradius-build:latest
+    volumes:
+    - ${DATA_PATH}/freeradius/homeserver/radiusd.conf:/etc/raddb/radiusd.conf
+    - ${DATA_PATH}/freeradius/env-setup.sh:/tmp/env-setup.sh
+    - ${LISTENER_DIR}/:/var/run/multi-server/
+    command: radiusd -X
+    restart: unless-stopped
+    entrypoint:
+    - bash
+    - -lc
+    - |
+      set -euo pipefail
+
+      # Next three lines based on test-framework test config example
+      source /tmp/env-setup.sh
+      export TEST_PROJECT_NAME=${COMPOSE_PROJECT_NAME}
+
+      exec /docker-entrypoint.sh "$@"
+      sleep infinity
+    <<: *id001
+{% endfor %}
+{% for i in range(1, (compose_num_of_proxy_servers + 1)) %}
+  proxy{{ i }}:
+    image: freeradius-build:latest
+    depends_on:
+    {% for i in range(1, (compose_num_of_home_servers + 1)) %}
+      - homeserver{{ i }}
+    {% endfor %}
+    volumes:
+    - ${DATA_PATH}/freeradius/proxy/radiusd.conf:/etc/raddb/radiusd.conf
+    - ${DATA_PATH}/freeradius/env-setup.sh:/tmp/env-setup.sh
+    - ${LISTENER_DIR}/:/var/run/multi-server/
+    command: radiusd -X
+    restart: unless-stopped
+    entrypoint:
+    - bash
+    - -lc
+    - |
+      set -euo pipefail
+
+      # Next three lines based on test-framework test config example
+      source /tmp/env-setup.sh
+      export TEST_PROJECT_NAME=${COMPOSE_PROJECT_NAME}
+
+      exec /docker-entrypoint.sh "$@"
+      sleep infinity
+    <<: *id001
+{% endfor %}
+  load-generator:
+    image: freeradius-build:latest
+    ports:
+      # Expose RADIUS ports for load generator to allow us to access the server from outside docker
+      - "1812:1812/udp"
+      - "1813:1813/udp"
+      - "1820:1820/udp"
+    depends_on:
+    {% for i in range(1, (compose_num_of_proxy_servers + 1)) %}
+      - proxy{{ i }}
+    {% endfor %}
+    volumes:
+    # load-generator templates
+    - ${DATA_PATH}/freeradius/load-generator/template.d/load-generator-templates:/etc/raddb/template.d/load-generator-templates
+
+    # Setup a testuser/testpass user for authentication testing with load-generator
+    # This is only really needed when testing the load-generator with radclient during development.
+    - ${DATA_PATH}/freeradius/load-generator/mods-config/files/authorize:/etc/raddb/mods-config/files/authorize
+
+    # load-generator server config
+    - ${DATA_PATH}/freeradius/load-generator/radiusd.conf:/etc/raddb/radiusd.conf
+
+    - ${DATA_PATH}/freeradius/env-setup.sh:/tmp/env-setup.sh
+    - ${DATA_PATH}/freeradius/load-generator/load-generator-packets/:/etc/raddb/load-generator-packets/
+    - ${LISTENER_DIR}/:/var/run/multi-server/
+    environment:
+      TEST_PROJECT_NAME: ${COMPOSE_PROJECT_NAME}
+      TEST_CONF_START_PPS: 5
+      TEST_CONF_MAX_PPS: 10
+      TEST_CONF_DURATION: 5
+      TEST_CONF_STEP: 5
+      TEST_CONF_PARALLEL: 1
+      TEST_CONF_MAX_BACKLOG: 1000
+      TEST_CONF_REPEAT: "no"
+    entrypoint:
+    - bash
+    - -lc
+    - |
+      set -euo pipefail
+
+      source /tmp/env-setup.sh
+      export TEST_PROJECT_NAME=${COMPOSE_PROJECT_NAME}
+
+      sleep infinity
+    <<: *id001
diff --git a/src/tests/multi-server/environments/docker-compose/env-5hs-autoaccept.yml.j2 b/src/tests/multi-server/environments/docker-compose/env-5hs-autoaccept.yml.j2
new file mode 100644 (file)
index 0000000..35b8e09
--- /dev/null
@@ -0,0 +1,87 @@
+# ---------------------------------------------------------------
+# Docker Compose Test Environment:
+#
+#                  --> HS1 (auto-accept)
+#
+#                  --> HS2 (auto-accept)
+#
+#   load-generator --> HS3 (auto-accept)
+#
+#                  --> HS4 (auto-accept)
+#
+#                  --> HS5 (auto-accept)
+#
+# ---------------------------------------------------------------
+x-common-config: &id001
+  cap_add:
+  - NET_ADMIN
+  - SYS_PTRACE
+services:
+{% for i in range(1, (compose_num_of_home_servers + 1)) %}
+  homeserver{{ i }}:
+    image: freeradius-build:latest
+    volumes:
+    - ${DATA_PATH}/freeradius/homeserver/radiusd.conf:/etc/raddb/radiusd.conf
+    - ${DATA_PATH}/freeradius/env-setup.sh:/tmp/env-setup.sh
+    - ${LISTENER_DIR}/:/var/run/multi-server/
+    command: radiusd -X
+    restart: unless-stopped
+    entrypoint:
+    - bash
+    - -lc
+    - |
+      set -euo pipefail
+
+      # Next three lines based on test-framework test config example
+      source /tmp/env-setup.sh
+      export TEST_PROJECT_NAME=${COMPOSE_PROJECT_NAME}
+
+      exec /docker-entrypoint.sh "$@"
+      sleep infinity
+    <<: *id001
+{% endfor %}
+  load-generator:
+    image: freeradius-build:latest
+    ports:
+      # Expose RADIUS ports for load generator to allow us to access the server from outside docker
+      - "1812:1812/udp"
+      - "1813:1813/udp"
+      - "1820:1820/udp"
+    depends_on:
+{% for i in range(1, (compose_num_of_home_servers + 1)) %}
+      - homeserver{{ i }}
+{% endfor %}
+    volumes:
+    # load-generator templates
+    - ${DATA_PATH}/freeradius/load-generator/template.d/load-generator-templates:/etc/raddb/template.d/load-generator-templates
+
+    # Setup a testuser/testpass user for authentication testing with load-generator
+    # This is only really needed when testing the load-generator with radclient during development.
+    - ${DATA_PATH}/freeradius/load-generator/mods-config/files/authorize:/etc/raddb/mods-config/files/authorize
+
+    # load-generator server config
+    - ${DATA_PATH}/freeradius/load-generator/radiusd.conf:/etc/raddb/radiusd.conf
+
+    - ${DATA_PATH}/freeradius/env-setup.sh:/tmp/env-setup.sh
+    - ${DATA_PATH}/freeradius/load-generator/load-generator-packets/:/etc/raddb/load-generator-packets/
+    - ${LISTENER_DIR}/:/var/run/multi-server/
+    environment:
+      TEST_PROJECT_NAME: ${COMPOSE_PROJECT_NAME}
+      TEST_CONF_START_PPS: 5
+      TEST_CONF_MAX_PPS: 10
+      TEST_CONF_DURATION: 5
+      TEST_CONF_STEP: 5
+      TEST_CONF_PARALLEL: 1
+      TEST_CONF_MAX_BACKLOG: 1000
+      TEST_CONF_REPEAT: "no"
+    entrypoint:
+    - bash
+    - -lc
+    - |
+      set -euo pipefail
+
+      source /tmp/env-setup.sh
+      export TEST_PROJECT_NAME=${COMPOSE_PROJECT_NAME}
+
+      sleep infinity
+    <<: *id001
diff --git a/src/tests/multi-server/environments/jinja-vars/env-1p-2hs-autoaccept.vars.yml b/src/tests/multi-server/environments/jinja-vars/env-1p-2hs-autoaccept.vars.yml
new file mode 100644 (file)
index 0000000..7d57ecb
--- /dev/null
@@ -0,0 +1,17 @@
+jinja_templates_to_render:
+  - environments/configs/freeradius/homeserver/radiusd.conf.j2
+  - environments/configs/freeradius/proxy/radiusd.conf.j2
+  - environments/configs/freeradius/load-generator/radiusd.conf.j2
+  - environments/docker-compose/env-1p-2hs-autoaccept.yml.j2
+
+# Docker compose Jinja template vars
+compose_num_of_home_servers: 2
+compose_num_of_proxy_servers: 1
+# Load generator Jinja template vars
+load_gen_num_of_dst_servers: 1
+load_gen_dst_server_name: proxy
+# Proxy server Jinja template vars
+proxy_num_of_dst_servers: 2
+proxy_dst_server_name: homeserver
+# General Jinja template vars
+listener_type: file
diff --git a/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml b/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml
new file mode 100644 (file)
index 0000000..2c6c2ea
--- /dev/null
@@ -0,0 +1,12 @@
+jinja_templates_to_render:
+  - environments/configs/freeradius/homeserver/radiusd.conf.j2
+  - environments/configs/freeradius/load-generator/radiusd.conf.j2
+  - environments/docker-compose/env-5hs-autoaccept.yml.j2
+
+# Docker compose Jinja template vars
+compose_num_of_home_servers: 5
+# Load generator Jinja template vars
+load_gen_num_of_dst_servers: 5
+load_gen_dst_server_name: homeserver
+# General Jinja template vars
+listener_type: file
diff --git a/src/tests/multi-server/test-1p-2hs-autoaccept-5min.yml b/src/tests/multi-server/test-1p-2hs-autoaccept-5min.yml
new file mode 100644 (file)
index 0000000..991df02
--- /dev/null
@@ -0,0 +1,69 @@
+timeout: 370
+state_order: sequence
+states:
+  state_1:
+    description: 5 minute load-generator test building off of baseline load-generator -> 1 proxy -> 2 home servers test. Home servers auto-accept requests.
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              #
+              # proto_load configuration via environment variables
+              #
+
+              export TEST_CONF_START_PPS=300
+              export TEST_CONF_MAX_PPS=350
+              # Duration must be equal or greater than max pps for proto_load to calculate "pps_accepted" effectively
+              export TEST_CONF_DURATION=60
+              export TEST_CONF_STEP=10
+              export TEST_CONF_PARALLEL=1
+              export TEST_CONF_MAX_BACKLOG=1000
+              export TEST_CONF_REPEAT="no"
+
+              TEST_CONF_NUM_MESSAGES=0
+              for ((pps=$TEST_CONF_START_PPS; pps<=$TEST_CONF_MAX_PPS; pps+=$TEST_CONF_STEP)); do
+                TEST_CONF_NUM_MESSAGES=$((TEST_CONF_NUM_MESSAGES + TEST_CONF_DURATION * pps))
+              done
+              export TEST_CONF_NUM_MESSAGES
+
+              #
+              # Delay to allow the rest of the environment to startup before starting load generation
+              #
+              sleep 20
+
+              #
+              # Starting load-generator server which will generate traffic based on env configuration
+              # from above.
+              #
+              /docker-entrypoint.sh &
+              tail -f /dev/null
+
+            detach: true
+    verify:
+      timeout: 360
+      trigger_mode: unordered
+  state_2:
+    description: Check load-generator Status-Server stats
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              # This command will query the load-generator's built-in Status-Server for statistics. Port 1820 configured to be used for Status-Server.
+              printf 'User-Name := "testuser"\nUser-Password := "testpass"' | /usr/bin/radclient -x localhost:1820 status testing123
+    verify:
+      timeout: 5
+      trigger_mode: unordered
+      triggers:
+      - load-generator-status-server:
+          json:
+            Status-Server-Result:
+              pattern:
+                reg_pattern: PASS
+            Access-Request-Counter:
+              pattern:
+                reg_pattern: (\d+)
+            Access-Accept-Counter:
+              pattern:
+                reg_pattern: (\d+)
diff --git a/src/tests/multi-server/test-1p-2hs-autoaccept.yml b/src/tests/multi-server/test-1p-2hs-autoaccept.yml
new file mode 100644 (file)
index 0000000..37349aa
--- /dev/null
@@ -0,0 +1,79 @@
+timeout: 50
+state_order: sequence
+states:
+  state_1:
+    description: Baseline load-generator test for load-generator -> 1 proxy -> 2 home servers. Home servers auto-accept requests.
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              #
+              # proto_load configuration via environment variables
+              #
+
+              export TEST_CONF_START_PPS=5
+              export TEST_CONF_MAX_PPS=10
+              # Duration must be equal or greater than max pps for proto_load to calculate "pps_accepted" effectively
+              export TEST_CONF_DURATION=5
+              export TEST_CONF_STEP=5
+              export TEST_CONF_PARALLEL=1
+              export TEST_CONF_MAX_BACKLOG=1000
+              export TEST_CONF_REPEAT="no"
+
+              TEST_CONF_NUM_MESSAGES=0
+              for ((pps=$TEST_CONF_START_PPS; pps<=$TEST_CONF_MAX_PPS; pps+=$TEST_CONF_STEP)); do
+                TEST_CONF_NUM_MESSAGES=$((TEST_CONF_NUM_MESSAGES + TEST_CONF_DURATION * pps))
+              done
+              export TEST_CONF_NUM_MESSAGES
+
+              #
+              # Delay to allow the rest of the environment to startup before starting load generation.
+              #
+              sleep 20
+
+              #
+              # Starting load-generator server which will generate traffic based on env configuration
+              # from above.
+              #
+              printf "Starting load-generator with the following configuration:\n"
+              printf "  Start PPS:        %s\n" "$TEST_CONF_START_PPS"
+              printf "  Max PPS:          %s\n" "$TEST_CONF_MAX_PPS"
+              printf "  Duration (secs):  %s\n" "$TEST_CONF_DURATION"
+              printf "  Step PPS:         %s\n" "$TEST_CONF_STEP"
+              printf "  Parallel:         %s\n" "$TEST_CONF_PARALLEL"
+              printf "  Max Backlog:      %s\n" "$TEST_CONF_MAX_BACKLOG"
+              printf "  Num Messages:     %s\n" "$TEST_CONF_NUM_MESSAGES"
+
+              freeradius &
+
+              tail -f /dev/null
+
+            detach: true
+    verify:
+      timeout: 40
+      trigger_mode: unordered
+  state_2:
+    description: Check load-generator Status-Server stats
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              # This command will query the load-generator's built-in Status-Server for statistics. Port 1820 configured to be used for Status-Server.
+              printf 'User-Name := "testuser"\nUser-Password := "testpass"' | /usr/bin/radclient -x localhost:1820 status testing123
+    verify:
+      timeout: 5
+      trigger_mode: unordered
+      triggers:
+      - load-generator-status-server:
+          json:
+            Status-Server-Result:
+              pattern:
+                reg_pattern: PASS
+            Access-Request-Counter:
+              pattern:
+                reg_pattern: (\d+)
+            Access-Accept-Counter:
+              pattern:
+                reg_pattern: (\d+)
diff --git a/src/tests/multi-server/test-5hs-autoaccept-5min.yml b/src/tests/multi-server/test-5hs-autoaccept-5min.yml
new file mode 100644 (file)
index 0000000..99f9dcf
--- /dev/null
@@ -0,0 +1,79 @@
+timeout: 370
+state_order: sequence
+states:
+  state_1:
+    description: 5 minute load-generator test building off of baseline load-generator -> 5 home servers test. Home servers auto-accept requests.
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              #
+              # proto_load configuration via environment variables
+              #
+
+              export TEST_CONF_START_PPS=300
+              export TEST_CONF_MAX_PPS=350
+              # Duration must be equal or greater than max pps for proto_load to calculate "pps_accepted" effectively
+              export TEST_CONF_DURATION=60
+              export TEST_CONF_STEP=10
+              export TEST_CONF_PARALLEL=1
+              export TEST_CONF_MAX_BACKLOG=1000
+              export TEST_CONF_REPEAT="no"
+
+              TEST_CONF_NUM_MESSAGES=0
+              for ((pps=$TEST_CONF_START_PPS; pps<=$TEST_CONF_MAX_PPS; pps+=$TEST_CONF_STEP)); do
+                TEST_CONF_NUM_MESSAGES=$((TEST_CONF_NUM_MESSAGES + TEST_CONF_DURATION * pps))
+              done
+              export TEST_CONF_NUM_MESSAGES
+
+              #
+              # Delay to allow the rest of the environment to startup before starting load generation.
+              #
+              sleep 20
+
+              #
+              # Starting load-generator server which will generate traffic based on env configuration
+              # from above.
+              #
+              printf "Starting load-generator with the following configuration:\n"
+              printf "  Start PPS:        %s\n" "$TEST_CONF_START_PPS"
+              printf "  Max PPS:          %s\n" "$TEST_CONF_MAX_PPS"
+              printf "  Duration (secs):  %s\n" "$TEST_CONF_DURATION"
+              printf "  Step PPS:         %s\n" "$TEST_CONF_STEP"
+              printf "  Parallel:         %s\n" "$TEST_CONF_PARALLEL"
+              printf "  Max Backlog:      %s\n" "$TEST_CONF_MAX_BACKLOG"
+              printf "  Num Messages:     %s\n" "$TEST_CONF_NUM_MESSAGES"
+
+              freeradius &
+
+              tail -f /dev/null
+
+            detach: true
+    verify:
+      timeout: 360
+      trigger_mode: unordered
+  state_2:
+    description: Check load-generator Status-Server stats
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              # This command will query the load-generator's built-in Status-Server for statistics. Port 1820 configured to be used for Status-Server.
+              printf 'User-Name := "testuser"\nUser-Password := "testpass"' | /usr/bin/radclient -x localhost:1820 status testing123
+    verify:
+      timeout: 5
+      trigger_mode: unordered
+      triggers:
+      - load-generator-status-server:
+          json:
+            Status-Server-Result:
+              pattern:
+                reg_pattern: PASS
+            Access-Request-Counter:
+              pattern:
+                reg_pattern: (\d+)
+            Access-Accept-Counter:
+              pattern:
+                reg_pattern: (\d+)
diff --git a/src/tests/multi-server/test-5hs-autoaccept.yml b/src/tests/multi-server/test-5hs-autoaccept.yml
new file mode 100644 (file)
index 0000000..6530541
--- /dev/null
@@ -0,0 +1,79 @@
+timeout: 50
+state_order: sequence
+states:
+  state_1:
+    description: Baseline load-generator test for load-generator -> 5 home servers. Home servers auto-accept requests.
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              #
+              # proto_load configuration via environment variables
+              #
+
+              export TEST_CONF_START_PPS=5
+              export TEST_CONF_MAX_PPS=10
+              # Duration must be equal or greater than max pps for proto_load to calculate "pps_accepted" effectively
+              export TEST_CONF_DURATION=5
+              export TEST_CONF_STEP=5
+              export TEST_CONF_PARALLEL=1
+              export TEST_CONF_MAX_BACKLOG=1000
+              export TEST_CONF_REPEAT="no"
+
+              TEST_CONF_NUM_MESSAGES=0
+              for ((pps=$TEST_CONF_START_PPS; pps<=$TEST_CONF_MAX_PPS; pps+=$TEST_CONF_STEP)); do
+                TEST_CONF_NUM_MESSAGES=$((TEST_CONF_NUM_MESSAGES + TEST_CONF_DURATION * pps))
+              done
+              export TEST_CONF_NUM_MESSAGES
+
+              #
+              # Delay to allow the rest of the environment to startup before starting load generation.
+              #
+              sleep 20
+
+              #
+              # Starting load-generator server which will generate traffic based on env configuration
+              # from above.
+              #
+              printf "Starting load-generator with the following configuration:\n"
+              printf "  Start PPS:        %s\n" "$TEST_CONF_START_PPS"
+              printf "  Max PPS:          %s\n" "$TEST_CONF_MAX_PPS"
+              printf "  Duration (secs):  %s\n" "$TEST_CONF_DURATION"
+              printf "  Step PPS:         %s\n" "$TEST_CONF_STEP"
+              printf "  Parallel:         %s\n" "$TEST_CONF_PARALLEL"
+              printf "  Max Backlog:      %s\n" "$TEST_CONF_MAX_BACKLOG"
+              printf "  Num Messages:     %s\n" "$TEST_CONF_NUM_MESSAGES"
+
+              freeradius &
+
+              tail -f /dev/null
+
+            detach: true
+    verify:
+      timeout: 40
+      trigger_mode: unordered
+  state_2:
+    description: Check load-generator Status-Server stats
+    host:
+      load-generator:
+        actions:
+        - execute_command:
+            command: |
+              # This command will query the load-generator's built-in Status-Server for statistics. Port 1820 configured to be used for Status-Server.
+              printf 'User-Name := "testuser"\nUser-Password := "testpass"' | /usr/bin/radclient -x localhost:1820 status testing123
+    verify:
+      timeout: 5
+      trigger_mode: unordered
+      triggers:
+      - load-generator-status-server:
+          json:
+            Status-Server-Result:
+              pattern:
+                reg_pattern: PASS
+            Access-Request-Counter:
+              pattern:
+                reg_pattern: (\d+)
+            Access-Accept-Counter:
+              pattern:
+                reg_pattern: (\d+)