diff --git a/bin/tests/system/checkds/tests_checkds.py b/bin/tests/system/checkds/tests_checkds.py index 7fc97747d8..c5e9806410 100755 --- a/bin/tests/system/checkds/tests_checkds.py +++ b/bin/tests/system/checkds/tests_checkds.py @@ -14,10 +14,10 @@ from typing import NamedTuple, Tuple import os -import subprocess import sys import time +import isctest import pytest pytest.importorskip("dns", minversion="2.0.0") @@ -86,7 +86,7 @@ def verify_zone(zone, transfer): # dnssec-verify command with default arguments. verify_cmd = [verify, "-z", "-o", zone, filename] - verifier = subprocess.run(verify_cmd, capture_output=True, check=True) + verifier = isctest.run.cmd(verify_cmd) if verifier.returncode != 0: print(f"error: dnssec-verify {zone}. failed") diff --git a/bin/tests/system/doth/conftest.py b/bin/tests/system/doth/conftest.py index 813be146f4..27dca7ee8a 100644 --- a/bin/tests/system/doth/conftest.py +++ b/bin/tests/system/doth/conftest.py @@ -12,9 +12,9 @@ # information regarding copyright ownership. import shutil -import subprocess import pytest +import isctest @pytest.fixture @@ -25,11 +25,8 @@ def gnutls_cli_executable(): pytest.skip("gnutls-cli not found in PATH") # Ensure gnutls-cli supports the --logfile command-line option. - output = subprocess.run( - [executable, "--logfile=/dev/null"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - check=False, + output = isctest.run.cmd( + [executable, "--logfile=/dev/null"], log_stderr=False, raise_on_exception=False ).stdout if b"illegal option" in output: pytest.skip("gnutls-cli does not support the --logfile option") diff --git a/bin/tests/system/doth/tests_sslyze.py b/bin/tests/system/doth/tests_sslyze.py index 2562fe482d..a904e7c12e 100644 --- a/bin/tests/system/doth/tests_sslyze.py +++ b/bin/tests/system/doth/tests_sslyze.py @@ -15,6 +15,7 @@ import os import pathlib import subprocess +import isctest import pytest @@ -46,12 +47,12 @@ def run_sslyze_in_a_loop(executable, port, log_file_prefix): # Run sslyze, logging stdout+stderr. Ignore the exit code since # sslyze is only used for triggering crashes here rather than # actual TLS analysis. - subprocess.run( + isctest.run.cmd( sslyze_args, stdout=sslyze_log, stderr=subprocess.STDOUT, timeout=30, - check=False, + raise_on_exception=False, ) # Ensure ns1 is still alive after each sslyze run. assert is_pid_alive(pid), f"ns1 (PID: {pid}) exited prematurely" diff --git a/bin/tests/system/include-multiplecfg/clean.sh b/bin/tests/system/include-multiplecfg/clean.sh index 905b2dd29a..62e1dcfd9d 100644 --- a/bin/tests/system/include-multiplecfg/clean.sh +++ b/bin/tests/system/include-multiplecfg/clean.sh @@ -15,7 +15,6 @@ # Clean up after allow query tests. # -rm -f dig.out.* rm -f ns*/named.conf rm -f */named.memstats rm -f ns*/named.lock diff --git a/bin/tests/system/include-multiplecfg/ns2/named.conf.in b/bin/tests/system/include-multiplecfg/ns2/named.conf.in index b38c228013..0dfe01d9a8 100644 --- a/bin/tests/system/include-multiplecfg/ns2/named.conf.in +++ b/bin/tests/system/include-multiplecfg/ns2/named.conf.in @@ -17,7 +17,7 @@ options { listen-on { 10.53.0.2; }; listen-on-v6 { none; }; recursion no; - notify no; + notify no; dnssec-validation no; }; diff --git a/bin/tests/system/include-multiplecfg/tests.sh b/bin/tests/system/include-multiplecfg/tests.sh deleted file mode 100644 index 8422417719..0000000000 --- a/bin/tests/system/include-multiplecfg/tests.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh - -# Copyright (C) Internet Systems Consortium, Inc. ("ISC") -# -# SPDX-License-Identifier: MPL-2.0 -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# See the COPYRIGHT file distributed with this work for additional -# information regarding copyright ownership. - -# Test of include statement with glob expression. - -set -e - -. ../conf.sh - -DIGOPTS="+tcp +nosea +nostat +nocmd +norec +noques +noadd +nostats -p ${PORT}" - -status=0 -n=0 - -# Test 1 - check if zone1 was loaded. -n=$((n + 1)) -echo_i "checking glob include of zone1 config ($n)" -ret=0 -$DIG $DIGOPTS @10.53.0.2 -b 10.53.0.2 zone1.com. a >dig.out.ns2.$n || ret=1 -grep 'status: NOERROR' dig.out.ns2.$n >/dev/null || ret=1 -grep '^zone1.com.' dig.out.ns2.$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Test 2 - check if zone2 was loaded. -n=$((n + 1)) -echo_i "checking glob include of zone2 config ($n)" -ret=0 -$DIG $DIGOPTS @10.53.0.2 -b 10.53.0.2 zone2.com. a >dig.out.ns2.$n || ret=1 -grep 'status: NOERROR' dig.out.ns2.$n >/dev/null || ret=1 -grep '^zone2.com.' dig.out.ns2.$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Test 3 - check if standard file path (no magic chars) works. -n=$((n + 1)) -echo_i "checking include of standard file path config ($n)" -ret=0 -$DIG $DIGOPTS @10.53.0.2 -b 10.53.0.2 mars.com. a >dig.out.ns2.$n || ret=1 -grep 'status: NOERROR' dig.out.ns2.$n >/dev/null || ret=1 -grep '^mars.com.' dig.out.ns2.$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Test 4: named-checkconf correctly parses glob includes. -n=$((n + 1)) -echo_i "checking named-checkconf with glob include ($n)" -ret=0 -( - cd ns2 - $CHECKCONF named.conf -) || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -echo_i "exit status: $status" -[ $status -eq 0 ] || exit 1 diff --git a/bin/tests/system/include-multiplecfg/tests_include_multiplecfg.py b/bin/tests/system/include-multiplecfg/tests_include_multiplecfg.py new file mode 100644 index 0000000000..346f33453e --- /dev/null +++ b/bin/tests/system/include-multiplecfg/tests_include_multiplecfg.py @@ -0,0 +1,39 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import os + +import isctest +import pytest + +import dns.message + + +@pytest.mark.parametrize( + "qname", + [ + "zone1.com.", # glob include of zone1 config + "zone2.com.", # glob include of zone2 config + "mars.com.", # checking include of standard file path config + ], +) +def test_include_multiplecfg(qname): + msg = dns.message.make_query(qname, "A") + res = isctest.query.tcp(msg, "10.53.0.2") + + isctest.check.noerror(res) + + assert res.answer[0] == dns.rrset.from_text(qname, 86400, "IN", "A", "10.53.0.1") + + +def test_include_multiplecfg_checkconf(): + """Test that named-checkconf correctly parses glob includes""" + isctest.run.cmd([os.environ["CHECKCONF"], "named.conf"], cwd="ns2") diff --git a/bin/tests/system/include-multiplecfg/tests_sh_include_multiplecfg.py b/bin/tests/system/include-multiplecfg/tests_sh_include_multiplecfg.py deleted file mode 100644 index e767c1d698..0000000000 --- a/bin/tests/system/include-multiplecfg/tests_sh_include_multiplecfg.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (C) Internet Systems Consortium, Inc. ("ISC") -# -# SPDX-License-Identifier: MPL-2.0 -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# See the COPYRIGHT file distributed with this work for additional -# information regarding copyright ownership. - - -def test_include_multiplecfg(run_tests_sh): - run_tests_sh() diff --git a/bin/tests/system/isctest/run.py b/bin/tests/system/isctest/run.py index 2efb39d137..e48e1c1b57 100644 --- a/bin/tests/system/isctest/run.py +++ b/bin/tests/system/isctest/run.py @@ -9,7 +9,56 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. +import subprocess import time +from typing import Optional + +import isctest.log + + +def cmd( # pylint: disable=too-many-arguments + args, + cwd=None, + timeout=60, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + log_stdout=False, + log_stderr=True, + input_text: Optional[bytes] = None, + raise_on_exception=True, +): + """Execute a command with given args as subprocess.""" + isctest.log.debug(f"command: {' '.join(args)}") + + def print_debug_logs(procdata): + if procdata: + if log_stdout and procdata.stdout: + isctest.log.debug( + f"~~~ cmd stdout ~~~\n{procdata.stdout.decode('utf-8')}\n~~~~~~~~~~~~~~~~~~" + ) + if log_stderr and procdata.stderr: + isctest.log.debug( + f"~~~ cmd stderr ~~~\n{procdata.stderr.decode('utf-8')}\n~~~~~~~~~~~~~~~~~~" + ) + + try: + proc = subprocess.run( + args, + stdout=stdout, + stderr=stderr, + input=input_text, + check=True, + cwd=cwd, + timeout=timeout, + ) + print_debug_logs(proc) + return proc + except subprocess.CalledProcessError as exc: + print_debug_logs(exc) + isctest.log.debug(f" return code: {exc.returncode}") + if raise_on_exception: + raise exc + return exc def retry_with_timeout(func, timeout, delay=1, msg=None): diff --git a/bin/tests/system/masterfile/tests_masterfile.py b/bin/tests/system/masterfile/tests_masterfile.py index 9843a47fbf..9aaaa769a5 100644 --- a/bin/tests/system/masterfile/tests_masterfile.py +++ b/bin/tests/system/masterfile/tests_masterfile.py @@ -10,7 +10,6 @@ # information regarding copyright ownership. import os -import subprocess import dns.message import dns.zone @@ -97,17 +96,14 @@ def test_masterfile_missing_master_file_servfail(): def test_masterfile_owner_inheritance(): """Test owner inheritance after $INCLUDE""" - checker_output = subprocess.run( + checker_output = isctest.run.cmd( [ os.environ["CHECKZONE"], "-D", "-q", "example", "zone/inheritownerafterinclude.db", - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - check=True, + ] ).stdout.decode("utf-8") owner_inheritance_zone = """ example. 0 IN SOA . . 0 0 0 0 0 diff --git a/bin/tests/system/rrchecker/tests_rrchecker.py b/bin/tests/system/rrchecker/tests_rrchecker.py index 743949aaf0..f425b83b91 100644 --- a/bin/tests/system/rrchecker/tests_rrchecker.py +++ b/bin/tests/system/rrchecker/tests_rrchecker.py @@ -10,8 +10,8 @@ # information regarding copyright ownership. import os -import subprocess +import isctest import pytest @@ -110,47 +110,37 @@ import pytest ], ) def test_rrchecker_list_standard_names(option, expected_result): - stdout = subprocess.run( - [ - os.environ["RRCHECKER"], - option, - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - check=True, - ).stdout.decode("utf-8") + stdout = isctest.run.cmd([os.environ["RRCHECKER"], option]).stdout.decode("utf-8") values = [line for line in stdout.split("\n") if line.strip()] assert sorted(values) == sorted(expected_result) def run_rrchecker(option, rr_class, rr_type, rr_rest): - with subprocess.Popen( - [os.environ["RRCHECKER"], option], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - ) as process: - rrchecker_output, _ = process.communicate( - f"{rr_class} {rr_type} {rr_rest}".encode("utf-8") + rrchecker_output = ( + isctest.run.cmd( + [os.environ["RRCHECKER"], option], + input_text=f"{rr_class} {rr_type} {rr_rest}".encode("utf-8"), ) - return rrchecker_output.decode("utf-8").split() + .stdout.decode("utf-8") + .strip() + ) + return rrchecker_output.split() @pytest.mark.parametrize("option", ["-p", "-u"]) def test_rrchecker_conversions(option): tempzone_file = "tempzone" with open(tempzone_file, "w", encoding="utf-8") as file: - subprocess.run( + isctest.run.cmd( [ os.environ["SHELL"], os.environ["TOP_SRCDIR"] + "/bin/tests/system/genzone.sh", "0", ], stdout=file, - stderr=subprocess.PIPE, - check=True, ) - checkzone_output = subprocess.run( + checkzone_output = isctest.run.cmd( [ os.environ["CHECKZONE"], "-D", @@ -158,9 +148,6 @@ def test_rrchecker_conversions(option): ".", tempzone_file, ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - check=True, ).stdout.decode("utf-8") checkzone_output = [ line for line in checkzone_output.splitlines() if not line.startswith(";") diff --git a/bin/tests/system/stress/tests_stress_update.py b/bin/tests/system/stress/tests_stress_update.py index 11044830d5..4c6f1f3694 100644 --- a/bin/tests/system/stress/tests_stress_update.py +++ b/bin/tests/system/stress/tests_stress_update.py @@ -11,7 +11,6 @@ import concurrent.futures import os -import subprocess import time import dns.query @@ -36,7 +35,7 @@ def rndc_loop(test_state, server): ] while not test_state["finished"]: - subprocess.run(cmdline, check=False) + isctest.run.cmd(cmdline, raise_on_exception=False) time.sleep(1)