bind9/bin/tests/system
Colin Vidal 588de09145 add strict bound check tests
Add checkconf system test covering the strict boundary checks for
`edns-version`, `edns-udp-size`, `max-udp-size`, `no-cookie-udp-size`
and `padding`.
2026-01-07 07:01:59 +00:00
..
_common Add a template for TA and generate it from isctest.kasp.Key 2025-11-27 14:02:49 +01:00
acl Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
additional Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
addzone Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
allow-query Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
auth Check delegation response to ANY query 2025-12-11 10:41:05 -08:00
autosign Use jinja2 templates in autosign test 2025-12-09 14:23:14 +01:00
bailiwick Test that spoofed DNAME is not accepted via spoofable transport 2025-12-22 11:58:39 +01:00
builtin Replace the trivial setup.sh system test files 2025-04-15 14:11:16 +02:00
cacheclean Disable DNSSEC validation instead of enabling it with empty TAs in tests 2025-07-06 14:18:10 +00:00
camp Replace the trivial setup.sh system test files 2025-04-15 14:11:16 +02:00
case Replace selected setup.sh system test files 2025-04-15 14:11:20 +02:00
catz Use jinja2 templates in catz test 2025-12-09 14:23:17 +01:00
cds Replace clean.sh files with extra_artifacts mark 2024-11-08 10:54:24 +01:00
chain Remove dnspython<2.0.0 compatibility hacks from custom servers 2025-12-18 13:03:14 +01:00
checkconf add strict bound check tests 2026-01-07 07:01:59 +00:00
checkconf-keys Use CmdResult to decode stdout/stderr from isctest.run.cmd() 2025-12-08 14:57:47 +01:00
checkds Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
checknames Disable DNSSEC validation instead of enabling it with empty TAs in tests 2025-07-06 14:18:10 +00:00
checkzone Use jinja2 templates in checkzone test 2025-12-09 14:23:14 +01:00
cipher-suites Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
configloading Refactor NamedInstance.rndc() to use EnvCmd() interface 2025-12-08 14:57:47 +01:00
cookie Use new AsyncDnsServer features in cookie system test 2025-12-18 13:13:59 +01:00
cpu Do not expect fail in cpu test default configuration 2025-06-25 11:35:27 +00:00
database Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
digdelv Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
dispatch Import dnspython modules explicitly in custom servers 2025-12-18 13:03:14 +01:00
dlzexternal Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
dns64 Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
dnssec Add isctest.kasp.SettimeOptions 2025-12-22 09:04:46 +00:00
dnssec-malformed-dnskey Test zone with truncated revoked DNSKEY 2026-01-05 14:04:58 +01:00
dnssectools move some test cases to different system tests 2025-07-31 12:55:40 -07:00
dnstap Use CmdResult to decode stdout/stderr from isctest.run.cmd() 2025-12-08 14:57:47 +01:00
doth Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
dsdigest Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
dyndb use a standard CLEANUP macro 2025-12-03 13:45:43 -08:00
ecdsa Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
eddsa Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
ede24 Use new EDE helper in existing system tests 2025-11-10 15:41:51 +01:00
ednscompliance Replace the trivial setup.sh system test files 2025-04-15 14:11:16 +02:00
emptyzones Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
enginepkcs11 Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
fetchlimit Import dnspython modules explicitly in custom servers 2025-12-18 13:03:14 +01:00
filters Use common name for post-startup server functions 2025-10-21 15:07:49 +02:00
formerr Replace the trivial setup.sh system test files 2025-04-15 14:11:16 +02:00
forward Import dnspython modules explicitly in custom servers 2025-12-18 13:03:14 +01:00
geoip2 Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
glue Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
hooks shrunk cfgobj down to 48bytes 2025-12-05 08:59:53 +01:00
host Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
idna Replace the trivial setup.sh system test files 2025-04-15 14:11:16 +02:00
include-multiplecfg Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
inline Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
integrity Replace the trivial setup.sh system test files 2025-04-15 14:11:16 +02:00
isctest Set default_aa on AsyncDnsServer to False by default 2026-01-05 13:27:57 +01:00
ixfr Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
journal Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
kasp Add isctest.kasp.SettimeOptions 2025-12-22 09:04:46 +00:00
keepalive Refactor NamedInstance.rndc() to use EnvCmd() interface 2025-12-08 14:57:47 +01:00
keyfromlabel Use Text with Grep support in isctest.run.cmd() 2025-12-08 14:57:47 +01:00
ksr Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
legacy Use jinja2 templates in legacy test 2025-12-09 14:23:17 +01:00
limits Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
logfileconfig Use jinja2 templates in logfileconf test 2025-12-09 14:23:14 +01:00
masterfile Use CmdResult to decode stdout/stderr from isctest.run.cmd() 2025-12-08 14:57:47 +01:00
masterformat Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
metadata Replace clean.sh files with extra_artifacts mark 2024-11-08 10:54:24 +01:00
migrate2kasp Make properties direct attribute of KeyProperties 2025-10-08 09:56:58 +02:00
mirror Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
mirror-root-zone Move root zone mirror system test to a separate directory 2025-06-27 15:19:45 +00:00
mkeys Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
multisigner Change notify-cds option to notify-cfg CDS 2025-12-29 10:06:16 +01:00
names Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
nohintswarn-bindchaos do not log "no root hints for view '_bind'" 2025-11-21 14:21:44 -08:00
notify Revert "Add ans6 blackhole server to notify system test" 2025-12-19 16:15:32 +01:00
nsec3 Adjust tests to new notify logs 2025-12-19 14:08:15 +01:00
nsec3-answer Don't use pytest.importorskip in isctest.name 2025-11-04 16:57:59 +01:00
nslookup Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
nsupdate Use jinja2 templates in nsupdate test 2025-12-09 14:23:14 +01:00
nta Refactor NamedInstance.rndc() to use EnvCmd() interface 2025-12-08 14:57:47 +01:00
nzd2nzf Refactor NamedInstance.rndc() to use EnvCmd() interface 2025-12-08 14:57:47 +01:00
optout Update optout test to reconfig to NSEC 2025-12-19 16:55:18 +01:00
padding Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
pending Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
pipelined standardize CHECK and RETERR macros 2025-12-03 13:26:28 -08:00
proxy Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
qmin Remove dnspython<2.0.0 compatibility hacks from custom servers 2025-12-18 13:03:14 +01:00
query-source Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
reclimit Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
redirect Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
resolver Use jinja2 templates in resolver test 2025-12-09 14:23:17 +01:00
rfc5011 add startup root DNSKEY refresh system test 2025-06-30 13:56:24 +02:00
rndc Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
rollover Change notify-cds option to notify-cfg CDS 2025-12-29 10:06:16 +01:00
rollover-algo-csk Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-algo-ksk-zsk Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-csk-roll1 Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-csk-roll2 Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-dynamic2inline rollover-dynamic2inline: Update templates 2025-12-19 11:47:50 +01:00
rollover-enable-dnssec Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-going-insecure Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-ksk-3crowd Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-ksk-doubleksk Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-lifetime Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-multisigner Add isctest.kasp.SettimeOptions 2025-12-22 09:04:46 +00:00
rollover-straight2none Test sending NOTIFY(CDS) messages during rollover 2025-12-19 15:01:36 +01:00
rollover-zsk-prepub Wait for "sending notifies" for step3.zsk-prepub 2025-12-31 11:40:42 +01:00
rootkeysentinel Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
rpz Use jinja2 templates in rpz test 2025-12-09 14:23:17 +01:00
rpzextra Change the QNAME minimization algorithm to follow the standard 2025-11-27 16:47:29 +01:00
rpzrecurse Import dnspython modules explicitly in custom servers 2025-12-18 13:03:14 +01:00
rrchecker Use CmdResult to decode stdout/stderr from isctest.run.cmd() 2025-12-08 14:57:47 +01:00
rrl Use pytest.mark.flaky as the flaky marker 2025-07-07 13:29:15 +02:00
rrsetorder Refactor the cyclic ordering to use query ID as offset 2025-09-08 14:04:13 +02:00
rrsig test for RRSIG provided as soon as they are found 2025-12-03 15:49:47 +01:00
rsabigexponent Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
runtime Use jinja2 templates in runtime test 2025-12-09 14:23:14 +01:00
selftest dns.name module does not have minversion attribute 2025-12-09 11:17:20 +01:00
serve-stale Use jinja2 templates in serve-stale test 2025-12-09 14:23:17 +01:00
sfcache update SERVFAIL cache test 2025-12-17 09:43:13 +01:00
showconf Refactor NamedInstance.rndc() to use EnvCmd() interface 2025-12-08 14:57:47 +01:00
shutdown Refactor NamedInstance.rndc() to use EnvCmd() interface 2025-12-08 14:57:47 +01:00
smartsign Replace clean.sh files with extra_artifacts mark 2024-11-08 10:54:24 +01:00
spf Refactor LogFile into TextFile with Grep support 2025-12-08 14:57:47 +01:00
staticstub Use jinja2 templates in staticstub test 2025-12-09 14:23:17 +01:00
statistics Import dnspython modules explicitly in custom servers 2025-12-18 13:03:14 +01:00
statschannel Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
stress Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
stub Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
synthfromdnssec Use jinja2 templates in synthfromdnssec test 2025-12-09 14:23:14 +01:00
synthrecord Exclude f.f.f.f.ip6.arpa names from test_sythreverse_refused_v6 2025-12-16 13:15:37 +11:00
tcp Use time.monotonic() for time measumeremts in pytest 2025-06-19 14:11:28 +02:00
timeouts Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
tools Use CmdResult to decode stdout/stderr from isctest.run.cmd() 2025-12-08 14:57:47 +01:00
transport-acl Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
transport-change Use jinja2 templates in transport-change test 2025-12-09 14:23:14 +01:00
tsig Add TSIG keyring support to AsyncDnsServer 2025-12-18 13:13:59 +01:00
tsiggss Use jinja2 templates in tsiggss 2025-12-09 14:23:14 +01:00
ttl Use isctest.query.create across system tests 2025-07-29 12:13:11 -07:00
unknown Replace the trivial setup.sh system test files 2025-04-15 14:11:16 +02:00
upforwd Replace .in with .j2 templates for cases with namedX.conf 2025-12-09 14:23:14 +01:00
verify Use Text with Grep support in isctest.run.cmd() 2025-12-08 14:57:47 +01:00
views Use jinja2 templates in views test 2025-12-09 14:23:17 +01:00
wildcard Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
xfer Add ans10 blackhole server to xfer system test 2026-01-06 21:17:48 +01:00
xfer-servers-list Adjust tests to new notify logs 2025-12-19 14:08:15 +01:00
xferquota Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
zero Import dnspython modules explicitly in custom servers 2025-12-18 13:03:14 +01:00
zonechecks Replace .in with .j2 templates for simple copy_setports cases 2025-12-09 14:23:14 +01:00
.gitignore replace the build system with meson 2025-06-11 10:30:12 +03:00
ans.pl Test xfrin's handing of EDNS failure scenarios 2023-10-20 18:16:25 +11:00
ans.py Add a reusable, bare-bones AsyncDnsServer 2025-12-22 11:58:39 +01:00
conf.sh Remove obsolete copy_setports 2025-12-09 14:23:17 +01:00
conftest.py Add TSAN report and core file globs to expected artifacts 2025-12-15 19:42:50 +01:00
digcomp.pl Update the copyright information in all files in the repository 2022-01-11 09:05:02 +01:00
ditch.pl Use a single local port for ditch.pl 2024-02-08 13:41:23 +01:00
feature-test.c Remove unused dlz-filesystem feature check 2025-12-08 18:07:41 +01:00
fromhex.pl Update the copyright information in all files in the repository 2022-01-11 09:05:02 +01:00
genzone.sh AMTRELAY type 0 presentation format handling was wrong 2025-11-20 18:28:32 +11:00
get_core_dumps.sh replace the build system with meson 2025-06-11 10:30:12 +03:00
ifconfig.sh.in Fix ifconfig.sh script 2025-07-17 07:36:40 +10:00
meson.build test for namedconf zone plugin support 2025-09-09 09:42:34 +02:00
org.isc.bind.system check 'update-policy 6to4-self' over IPv6 2024-08-01 15:17:30 +10:00
org.isc.bind.system.plist
packet.pl Update the copyright information in all files in the repository 2022-01-11 09:05:02 +01:00
pytest.ini Add pytest fixture for checking test artifacts 2024-11-08 10:54:24 +01:00
re_compile_checker.py Add pylint check for re.compile() alias 2025-12-08 14:57:47 +01:00
README.md Remove obsolete copy_setports 2025-12-09 14:23:17 +01:00
run.gdb Dump the backtrace to stdout when core is found in systest directory 2019-11-21 02:05:47 +08:00
run.sh Prevent .hypothesis artifacts in system test directories 2025-06-03 07:35:18 +00:00
send.pl Update the copyright information in all files in the repository 2022-01-11 09:05:02 +01:00
start.pl convert dnssec validation tests to python 2025-07-31 12:55:40 -07:00
start.sh.in Update the copyright information in all files in the repository 2022-01-11 09:05:02 +01:00
stop.pl replace the build system with meson 2025-06-11 10:30:12 +03:00
stop.sh.in replace the build system with meson 2025-06-11 10:30:12 +03:00
testsock.pl Look for ifconfig.sh.in in testsock.pl parent dir 2023-01-13 17:01:30 +01:00
testsock6.pl IO::Socket::INET6 has been replaced by IO::Socket::IP 2023-09-13 14:31:43 +10:00
vulture_ignore_list.py Rewrite keyfromlabel system test to pytest 2025-02-17 19:18:04 +00:00
wire-test.c Change the 'isc_g_mctx' to be always available 2025-08-04 11:29:50 +02:00

BIND9 System Test Framework

This directory holds test environments for running bind9 system tests involving multiple name servers.

Each system test directory holds a set of scripts and configuration files to test different parts of BIND. The directories are named for the aspect of BIND they test, for example:

dnssec/       DNSSEC tests
forward/      Forwarding tests
glue/         Glue handling tests

etc.

A system test directory must start with an alphabetic character and may not contain any special characters. Only hyphen may be used as a word separator.

Typically each set of tests sets up 2-5 name servers and then performs one or more tests against them. Within the test subdirectory, each name server has a separate subdirectory containing its configuration data. These subdirectories are named "nsN" or "ansN" (where N is a number between 1 and 8, e.g. ns1, ans2 etc.)

The tests are completely self-contained and do not require access to the real DNS. Generally, one of the test servers (usually ns1) is set up as a root nameserver and is listed in the hints file of the others.

Running the Tests

Prerequisites

To run system tests, make sure you have the following dependencies installed:

  • python3
  • pytest
  • perl
  • dnspython
  • pytest-xdist (for parallel execution)
  • python-jinja2

Individual system tests might also require additional dependencies. If those are missing, the affected tests will be skipped and should produce a message specifying what additional prerequisites they expect.

Network Setup

To enable all servers to run on the same machine, they bind to separate virtual IP addresses on the loopback interface. ns1 runs on 10.53.0.1, ns2 on 10.53.0.2, etc. Before running any tests, you must set up these addresses by running the command

sh ifconfig.sh up

as root. The interfaces can be removed by executing the command:

sh ifconfig.sh down

... also as root.

The servers use unprivileged ports (above 1024) instead of the usual port 53, so they can be run without root privileges once the interfaces have been set up.

Note for MacOS Users

If you wish to make the interfaces survive across reboots, copy org.isc.bind.system and org.isc.bind.system.plist to /Library/LaunchDaemons then run

launchctl load /Library/LaunchDaemons/org.isc.bind.system.plist

... as root.

Running a Single Test

The recommended way is to use pytest and its test selection facilities:

pytest -k <test-name-or-pattern>

Using -k to specify a pattern allows to run a single pytest test case within a system test. E.g. you can use -k test_sslyze_dot to execute just the test_sslyze_dot() function from doth/tests_sslyze.py.

However, using the -k pattern might pick up more tests than intended. You can use the --collect-only option to check the list of tests which match you -k pattern. If you just want to execute all system tests within a single test directory, you can also use the utility script:

./run.sh system_test_dir_name

Running All the System Tests

Issuing plain pytest command without any argument will execute all tests sequentially. To execute them in parallel, ensure you have pytest-xdist installed and run:

pytest [-n <number-of-workers>]

Alternately, using the make command is also supported:

make [-j numproc] test

rr

When running system tests, named can be run under the rr tool. rr records a trace to the $system_test/nsX/named-Y/ directory, which can be later used to replay named. To enable this, execute start.pl with the USE_RR environment variable set.

Test Artifacts

Each test module is executed inside a unique temporary directory which contains all the artifacts from the test run. If the tests succeed, they are deleted by default. To override this behaviour, pass --noclean to pytest.

The directory name starts with the system test name, followed by _tmp_XXXXXX, i.e. dns64_tmp_r07vei9s for dns64 test run. Since this name changes each run, a convenience symlink that has a stable name is also created. It points to the latest test artifacts directory and has a form of dns64_sh_dns64 (depending on the particular test module).

To clean up the temporary directories and symlinks, run make clean-local in the system test directory.

The following test artifacts are typically available:

  • pytest.log.txt: main log file with test output
  • files generated by the test itself, e.g. output from "dig" and "rndc"
  • files produced by named, other tools or helper scripts

Writing System Tests

File Overview

Tests are organized into system test directories which may hold one or more test modules (python files). Each module may have multiple test cases. The system test directories may contain the following standard files:

  • tests_*.py: These python files are picked up by pytest as modules. If they contain any test functions, they're added to the test suite.

  • *.j2: These jinja2 templates can be used for configuration files or any other files which require certain variables filled in, e.g. ports from the environment variables. During test setup, the pytest runner will automatically fill those in and strip the filename extension .j2, e.g. ns1/named.conf.j2 becomes ns1/named.conf. When using advanced templating to conditionally include/omit entire sections or when filling in custom variables used for the test, ensure the templates always include the defaults. If you don't need the file to be auto-templated during test setup, use .j2.manual instead and then no defaults are needed.

  • setup.sh: This sets up the preconditions for the tests.

  • tests.sh: Any shell-based tests are located within this file. Runs the actual tests.

  • tests_sh_*.py: A glue file for the pytest runner for executing shell tests.

  • ns<N>: These subdirectories contain test name servers that can be queried or can interact with each other. The value of N indicates the address the server listens on: for example, ns2 listens on 10.53.0.2, and ns4 on 10.53.0.4. All test servers use an unprivileged port, so they don't need to run as root. These servers log at the highest debug level and the log is captured in the file "named.run".

  • ans<N>: Like ns[X], but these are simple mock name servers implemented in Perl or Python. They are generally programmed to misbehave in ways named would not so as to exercise named's ability to interoperate with badly behaved name servers.

Module Scope

A module is a python file which contains test functions. Every system test directory may contain multiple modules (i.e. tests_*.py files).

The server setup/teardown is performed for each module. Bundling test cases together inside a single module may save some resources. However, test cases inside a single module can't be executed in parallel.

It is possible to execute different modules defined within a single system test directory in parallel. This is possible thanks to executing the tests inside a temporary directory and proper port assignment to ensure there won't be any conflicts.

Port Usage

In order for the tests to run in parallel, each test requires a unique set of ports. This is ensured by the pytest runner, which assigns a unique set of ports to each test module.

Inside the python tests, it is possible to use the ports fixture to get the assigned port numbers. They're also set as environment variables. These include:

  • PORT: used as the basic dns port
  • TLSPORT: used as the port for DNS-over-TLS
  • HTTPPORT, HTTPSPORT: used as the ports for DNS-over-HTTP
  • CONTROLPORT: used as the RNDC control port
  • EXTRAPORT1 through EXTRAPORT8: additional ports that can be used as needed

Logging

Each module has a separate log which will be saved as pytest.log.txt in the temporary directory in which the test is executed. This log includes messages for this module setup/teardown as well as any logging from the tests. Logging level DEBUG and above will be present in this log.

In general, any log messages using INFO or above will also be printed out during pytest execution. In CI, the pytest output is also saved to pytest.out.txt in the bin/tests/system directory.

Adding a Test to the System Test Suite

Once a test has been created it will be automatically picked up by the pytest runner if it upholds the convention expected by pytest (especially when it comes to naming files and test functions).

However, if a new system test directory is created, it also needs to be added to TESTS in Makefile.am, in order to work with make check.

Test Files

setup.sh

This script is responsible for setting up the configuration files used in the test. It is used by both the python and shell tests. It is interpreted just before the servers are started up for each test module.

tests_*.py

These are test modules containing tests written in python. Every test is a function which begins with the name test_ (according to pytest convention). It is possible to pass fixtures to the test function by specifying their name as function arguments. Fixtures are used to provide context to the tests, e.g.:

  • ports is a dictionary with assigned port numbers

tests_sh_*.py

These are glue files that are required to execute shell based tests (see below). These modules shouldn't contain any python tests (use a separate file instead).

tests.sh

This is the test file for shell based tests.

Nameservers

As noted earlier, a system test will involve a number of nameservers. These will be either instances of named, or special servers written in a language such as Perl or Python.

For the former, the version of "named" being run is that in the "bin/named" directory in the tree holding the tests (i.e. if "make test" is being run immediately after "make", the version of "named" used is that just built). The configuration files, zone files etc. for these servers are located in subdirectories of the test directory named "nsN", where N is a small integer. The latter are special nameservers, mostly used for generating deliberately bad responses, located in subdirectories named "ansN" (again, N is an integer). In addition to configuration files, these directories should hold the appropriate script files as well.

Note that the "N" for a particular test forms a single number space, e.g. if there is an "ns2" directory, there cannot be an "ans2" directory as well. Ideally, the directory numbers should start at 1 and work upwards.

When tests are executed, pytest takes care of the test setup and teardown. It looks for any nsN and ansN directories in the system test directory and starts those servers.

named Command-Line Options

By default, named server is started with the following options:

-c named.conf   Specifies the configuration file to use (so by implication,
                each "nsN" nameserver's configuration file must be called
                named.conf).

-d 99           Sets the maximum debugging level.

-D <name>       The "-D" option sets a string used to identify the
                nameserver in a process listing.  In this case, the string
                is the name of the subdirectory.

-g              Runs the server in the foreground and logs everything to
                stderr.

-m record
                Turns on these memory usage debugging flags.

All output is sent to a file called named.run in the nameserver directory.

The options used to start named can be altered. There are a couple ways of doing this. start.pl checks the methods in a specific order: if a check succeeds, the options are set and any other specification is ignored. In order, these are:

  1. Specifying options to start.pl or start_server shell utility function after the name of the test directory, e.g.

    start_server --noclean --restart --port ${PORT} ns1 -- "-D xfer-ns1 -T transferinsecs -T transferslowly"

  2. Including a file called "named.args" in the "nsN" directory. If present, the contents of the first non-commented, non-blank line of the file are used as the named command-line arguments. The rest of the file is ignored.

  3. Tweaking the default command line arguments with "-T" options. This flag is used to alter the behavior of BIND for testing and is not documented in the ARM. The presence of certain files in the "nsN" directory adds flags to the default command line (the content of the files is irrelevant - it is only the presence that counts):

    named.noaa Appends "-T noaa" to the command line, which causes "named" to never set the AA bit in an answer.

    named.dropedns Adds "-T dropedns" to the command line, which causes "named" to recognise EDNS options in messages, but drop messages containing them.

    named.maxudp1460 Adds "-T maxudp1460" to the command line, setting the maximum UDP size handled by named to 1460.

    named.maxudp512 Adds "-T maxudp512" to the command line, setting the maximum UDP size handled by named to 512.

    named.noedns Appends "-T noedns" to the command line, which disables recognition of EDNS options in messages.

    named.notcp Adds "-T notcp", which disables TCP in "named".

    named.soa Appends "-T nosoa" to the command line, which disables the addition of SOA records to negative responses (or to the additional section if the response is triggered by RPZ rewriting).

Running Nameservers Interactively

In order to debug the nameservers, you can let pytest perform the nameserver setup and interact with the servers before the test starts, or even at specific points during the test, using the --trace option to drop you into pdb debugger which pauses the execution of the tests, while keeping the server state intact:

pytest -k dns64 --trace

Developer Notes

Test discovery and collection

There are two distinct types of system tests. The first is a shell script tests.sh containing individual test cases executed sequentially and the success/failure is determined by return code. The second type is a regular pytest file which contains test functions.

Dealing with the regular pytest files doesn't require any special consideration as long as the naming conventions are met. Discovering the tests.sh tests is more complicated.

The chosen solution is to add a bit of glue for each system test. For every tests.sh, there is an accompanying tests_sh_*.py file that contains a test function which utilizes a custom run_tests_sh fixture to call the tests.sh script. Other solutions were tried and eventually rejected. While this introduces a bit of extra glue, it is the most portable, compatible and least complex solution.

Compatibility with older pytest version

Keep in mind that the pytest runner must work with ancient versions of pytest. When implementing new features, it is advisable to check feature support in pytest and pytest-xdist in older distributions first.

As a general rule, any changes to the pytest runner need to keep working on all platforms in CI that use the pytest runner. As of 2023-11-14, the oldest supported version is whatever is available in EL8.

We may need to add more compat code eventually to handle breaking upstream changes. For example, using request.fspath attribute is already deprecated in latest pytest.

Format of Shell Test Output

Shell-based tests have the following format of output:

<letter>:<test-name>:<message> [(<number>)]

e.g.

I:catz:checking that dom1.example is not served by primary (1)

The meanings of the fields are as follows:

This indicates the type of message. This is one of:
S   Start of the test
A   Start of test (retained for backwards compatibility)
T   Start of test (retained for backwards compatibility)
E   End of the test
I   Information.  A test will typically output many of these messages
    during its run, indicating test progress.  Note that such a message may
    be of the form "I:testname:failed", indicating that a sub-test has
    failed.
R   Result.  Each test will result in one such message, which is of the
    form:

            R:<test-tmpdir>:<result>

    where <result> is one of:

        PASS        The test passed
        FAIL        The test failed
        SKIPPED     The test was not run, usually because some
                    prerequisites required to run the test are missing.
This is the name of the temporary test directory from which the message emanated, which is also the name of the subdirectory holding the test files. This is text output by the test during its execution.

() If present, this will correlate with a file created by the test. The tests execute commands and route the output of each command to a file. The name of this file depends on the command and the test, but will usually be of the form:

<command>.out.<suffix><number>

e.g. nsupdate.out.test28, dig.out.q3. This aids diagnosis of problems by allowing the output that caused the problem message to be identified.