Skip to content

Commit 370225b

Browse files
committed
multi-server: refactor test framework for parameterised tests
Restructure the multi-server test framework so that each test is defined by a single YAML params file. All templates (compose, radiusd configs, test steps) are rendered from shared Jinja2 templates using those params. - Replace monolithic all.mk with macro-based framework that auto-discovers test suites and param files - Move configs to configs/freeradius/, environments to environments/ - Rename test suites to proxy-accept and proxy-multihop-accept - Use *.test.yml for param files, *.ci.test.yml for CI-only tests - Add test.multi-server.ci target for short CI tests - Render all build products into build/ directory - Support parallel execution with unique Docker project names - Add healthchecks to compose templates - Remove hardcoded port mappings (containers use internal networking) - Add CI workflow for GitHub Actions with Docker-in-Docker
1 parent 7982e1b commit 370225b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+388
-1597
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
name: Multi-Server CI Tests
2+
3+
on:
4+
push:
5+
branches-ignore:
6+
- coverity_scan
7+
- run-fuzzer**
8+
- debug-fuzzer-**
9+
pull_request:
10+
paths:
11+
- '.github/workflows/ci-multi-server-tests.yml'
12+
- 'src/tests/multi-server/**'
13+
workflow_dispatch:
14+
15+
jobs:
16+
multi-server-tests:
17+
runs-on: self-hosted
18+
19+
services:
20+
dind:
21+
image: docker:dind
22+
options: --privileged
23+
env:
24+
DOCKER_TLS_CERTDIR: ""
25+
# Bypass the squid proxy for internal registry access.
26+
NO_PROXY: "*.networkradius.com,127.0.0.1"
27+
# Mount the host's internal CA so dind trusts
28+
# docker.internal.networkradius.com for image pulls.
29+
#
30+
# Share the runner's workspace with dind so that docker
31+
# compose bind-mounts (radiusd.conf, env-setup.sh, listener
32+
# dirs, etc.) resolve to real files inside the dind daemon.
33+
#
34+
# github.workspace is the HOST path to the workspace.
35+
# The runner mounts it into the job container at a
36+
# different path (/__w/...), so we use a fixed mount
37+
# point (/workspace) that both containers agree on.
38+
volumes:
39+
- /usr/local/share/ca-certificates/networkradius.com.crt:/etc/docker/certs.d/docker.internal.networkradius.com/ca.crt:ro
40+
- ${{ github.workspace }}:/workspace
41+
42+
container:
43+
image: docker.internal.networkradius.com/self-hosted
44+
# "privileged" is needed for Samba install
45+
# "memory-swap -1" enables full use of host swap and may help
46+
# with containers randomly quitting with "The operation was
47+
# canceled"
48+
options: >-
49+
--privileged
50+
--memory-swap -1
51+
env:
52+
DOCKER_HOST: tcp://dind:2375
53+
NO_PROXY: dind
54+
# Shared workspace — see dind volumes comment above.
55+
volumes:
56+
- ${{ github.workspace }}:/workspace
57+
58+
defaults:
59+
run:
60+
working-directory: /workspace
61+
62+
steps:
63+
64+
- name: Install extra packages
65+
run: |
66+
apt-get update && apt-get install -y --no-install-recommends docker.io docker-buildx docker-compose-v2 python3-venv
67+
68+
- uses: actions/checkout@v4
69+
with:
70+
lfs: false
71+
72+
# Authenticate to the internal registry via the dind daemon.
73+
# The host Docker daemon is logged in via the runner's
74+
# job-started hook, but dind is a separate daemon with no
75+
# auth config.
76+
- name: Login to internal Docker registry
77+
env:
78+
DOCKER_USERNAME: ${{ secrets.DOCKER_REPO_USERNAME }}
79+
DOCKER_PASSWORD: ${{ secrets.DOCKER_REPO_PASSWORD }}
80+
run: |
81+
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin https://docker.internal.networkradius.com/
82+
83+
- name: Build Docker image from source
84+
run: |
85+
make docker.ubuntu24.build
86+
docker tag freeradius4/ubuntu24:latest freeradius-build:latest
87+
88+
- name: Run multi-server tests
89+
run: |
90+
make -j$(nproc) test.multi-server.ci
91+
92+
#
93+
# If the CI has failed and the branch is ci-debug
94+
# then start a tmate session for interactive debugging.
95+
#
96+
- name: "Debug: Start tmate"
97+
uses: mxschmitt/action-tmate@v3
98+
with:
99+
limit-access-to-actor: true
100+
if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}

Makefile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ endif
4343
# there's no point in requiring the developer to run configure
4444
# *before* making packages.
4545
#
46-
ifeq "$(filter deb rpm pkg_version dist-check% crossbuild.% docker.% freeradius-server-%,$(MAKECMDGOALS))" ""
46+
# Multi-server tests use Docker and don't need a local build.
47+
#
48+
ifeq "$(filter deb rpm pkg_version dist-check% crossbuild.% docker.% freeradius-server-% test.multi-server%,$(MAKECMDGOALS))" ""
4749
$(if $(wildcard Make.inc),,$(error Missing 'Make.inc' Run './configure [options]' and retry))
4850
include Make.inc
4951
else
@@ -112,10 +114,10 @@ PROTOCOLS := \
112114
tls
113115

114116
#
115-
# If we're building packages or crossbuilding, just do that.
116-
# Don't try to do a local build.
117+
# If we're building packages, crossbuilding, or running Docker-based
118+
# tests, just do that. Don't try to do a local build.
117119
#
118-
ifeq "$(filter deb rpm pkg_version dist-check% crossbuild.% docker.% freeradius-server-%,$(MAKECMDGOALS))" ""
120+
ifeq "$(filter deb rpm pkg_version dist-check% crossbuild.% docker.% freeradius-server-% test.multi-server%,$(MAKECMDGOALS))" ""
119121

120122
#
121123
# Include all of the autoconf definitions into the Make variable space
@@ -575,3 +577,10 @@ endif
575577
ifneq "$(findstring docker,$(MAKECMDGOALS))" ""
576578
include scripts/docker/docker.mk
577579
endif
580+
581+
#
582+
# Multi-server integration tests (Docker-based, no configure needed)
583+
#
584+
ifneq "$(findstring test.multi-server,$(MAKECMDGOALS))" ""
585+
include src/tests/multi-server/all.mk
586+
endif

src/tests/multi-server/README.md

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,82 @@
1-
If you are reading this, you are probably wondering how to run a multi-server test. Here's a quick overview.
1+
# Multi-Server Tests
22

3-
## Before You Begin
3+
Integration tests that spin up multiple FreeRADIUS instances in Docker
4+
containers and verify they can proxy traffic between each other.
45

5-
Running the multi-server tests requires the availability of a Docker
6-
image `freeradius-build:latest` to be available on the host running
7-
the tests.
6+
## Prerequisites
7+
8+
A `freeradius-build:latest` Docker image must be available locally:
89

910
```bash
10-
% cd ${FREERADIUS-SERVER-LOCAL-REPO}
11-
% make docker.ubuntu24.build
12-
% docker tag <your-freeradius-docker-image-tag> freeradius-build:latest
11+
make docker.ubuntu24.build
12+
docker tag freeradius4/ubuntu24:latest freeradius-build:latest
1313
```
1414

15-
## Run Test With Makefile
16-
17-
### Run All Tests
15+
## Running Tests
1816

19-
2. Run make target based on the test name. All testcase config files
20-
start with "test-*".
17+
### All tests
2118

2219
```bash
23-
% make -f src/tests/multi-server/all.mk
20+
make test.multi-server
2421
```
2522

26-
### Run Specific Tests (Example)
23+
### CI tests only (short tests)
2724

2825
```bash
29-
% make -f src/tests/multi-server/all.mk test-5hs-autoaccept
26+
make test.multi-server.ci
3027
```
3128

32-
or
29+
### A specific test
3330

3431
```bash
35-
% make -f src/tests/multi-server/all.mk test-1p-2hs-autoaccept
32+
make test.multi-server.proxy-accept.short.ci
3633
```
3734

38-
### Optional Debug Logs and Logging Verbosity Level
35+
### Parallel execution
3936

4037
```bash
41-
% make -f src/tests/multi-server/all.mk test-5hs-autoaccept DEBUG=1 VERBOSE=4
38+
make -j$(nproc) test.multi-server
4239
```
4340

44-
## Run Multi-Server Tests Manually Without Makefile (Optional)
41+
### Extra flags
4542

46-
### Clone Multi-Server Test Framework Repo & Activate Python venv
43+
Pass debug/verbosity flags to the test framework:
4744

4845
```bash
49-
cd src/tests/multi-server/
50-
git clone git@github.com:InkbridgeNetworks/freeradius-multi-server.git
51-
cd freeradius-multi-server
52-
./configure
53-
source .venv/bin/activate
46+
make test.multi-server TEST_MULTI_SERVER_FLAGS="-xx -vvv"
5447
```
5548

56-
### Render Jinja Templates
49+
## How It Works
5750

58-
In this example we render the Jinja templates used by the environment
59-
configuration used by the `test-5hs-autoaccept` test.
51+
Each test suite is a directory under `tests/` containing:
6052

61-
The Docker Compose `env-5hs-autoaccept.yml` file represents the
62-
`load-generator -> 5 homeserver` test environment used by the test.
53+
- `template.yml.j2` - Jinja2 template for test steps (state machine)
54+
- `environment.yml.j2` - Symlink to a Docker Compose template in `environments/`
55+
- `*.test.yml` - Parameter files (one per test variant)
6356

64-
Render FreeRADIUS "homeserver" Virtual Server config:
57+
A parameter file is flat YAML defining topology, load profile, and test
58+
timeouts. All `.j2` files in the suite directory are rendered using
59+
these parameters. The rendered compose file's `${DATA_PATH}` volume
60+
mounts are scanned and the corresponding config files are copied or
61+
rendered into the build directory.
6562

66-
```bash
67-
% python3 src/config_builder.py \
68-
--vars-file "${top_srcdir}/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml" \
69-
--aux-file "${top_srcdir}/src/tests/multi-server/environments/configs/freeradius/homeserver/radiusd.conf.j2" \
70-
--include-path "${top_srcdir}/src/tests/multi-server/"
71-
```
72-
Render FreeRADIUS "load-generator" Virtual Server config:
73-
```bash
74-
python3 src/config_builder.py \
75-
--vars-file "${top_srcdir}/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml" \
76-
--aux-file "${top_srcdir}/src/tests/multi-server/environments/configs/freeradius/load-generator/radiusd.conf.j2" \
77-
--include-path "${top_srcdir}/src/tests/multi-server/"
78-
```
63+
Build outputs go to `build/tests/multi-server/<suite>/<test>/`.
7964

80-
Render Docker Compose environment:
65+
## Adding a New Test
8166

82-
```bash
83-
python3 src/config_builder.py \
84-
--vars-file "${top_srcdir}/src/tests/multi-server/environments/jinja-vars/env-5hs-autoaccept.vars.yml" \
85-
--aux-file "${top_srcdir}/src/tests/multi-server/environments/docker-compose/env-5hs-autoaccept.yml.j2" \
86-
--include-path "${top_srcdir}/src/tests/multi-server/"
87-
```
67+
1. Create a parameter file in an existing suite directory, e.g.
68+
`tests/proxy-accept/heavy.test.yml`. Name it `*.ci.test.yml` if
69+
it should run in CI.
8870

89-
### Run the test:
71+
2. Or create a new suite directory with `template.yml.j2`,
72+
`environment.yml.j2` (symlink), and parameter files.
9073

91-
```bash
92-
% DATA_PATH="${top_srcdir}/src/tests/multi-server/environments/configs" \
93-
make test-framework -- -x -v \
94-
--compose "${top_srcdir}/src/tests/multi-server/environments/docker-compose/env-5hs-autoaccept.yml" \
95-
--test "${top_srcdir}/src/tests/multi-server/test-5hs-autoaccept.yml" \
96-
--use-files \
97-
--listener-dir "${top_srcdir}/build/tests/multi-server/freeradius-multi-server-test-runtime-logs/test-5hs-autoaccept"
98-
```
74+
The build framework discovers suites automatically by finding
75+
directories containing `template.yml.j2`, and discovers tests by
76+
finding `*.test.yml` files within them.
77+
78+
## File Naming Conventions
79+
80+
- `*.test.yml` - Test parameter file (discovered by `make test.multi-server`)
81+
- `*.ci.test.yml` - CI test parameter file (also discovered by `make test.multi-server.ci`)
82+
- `*.yml.j2` - Jinja2 template (rendered, not treated as a test)

0 commit comments

Comments
 (0)