Commit cc9278ff92 for bind

commit cc9278ff92de60020ee6e85c2b918aecb86f0c65
Author: Štěpán Balážik <stepan@isc.org>
Date:   Wed Sep 16 17:31:15 2026 +0200

    Move the asyncserver self-tests into the package

    The tests in selftest_asyncdnsserver exercise isctest.asyncserver only,
    so keep them next to the code, as isctest/asyncserver/tests/dnssec.
    Let the system test fixtures derive the test name from the path
    relative to bin/tests/system, so that a test directory may live deeper
    in the tree; the temporary run directory and the convenience symlink
    are still created directly under bin/tests/system.

    The doctest CI job runs pytest inside isctest/ without the system test
    conftest, so it now skips the tests/ directories, which the system test
    jobs run.

    Assisted-by: Claude:claude-fable-5-1

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eccc69f648..ddb3782520 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -777,8 +777,9 @@ doctest:
     - *find_pytest
     - cd bin/tests/system/isctest
     - RET=0
+    # The tests/ directories hold system tests, run by the system test jobs.
     - >
-      "$PYTEST" --noconftest --doctest-modules --junit-xml="$CI_PROJECT_DIR/junit_doctest.xml" || RET=1
+      "$PYTEST" --noconftest --doctest-modules --ignore=tests --ignore-glob='*/tests' --junit-xml="$CI_PROJECT_DIR/junit_doctest.xml" || RET=1
     - *git_clone_bind9-qa
     - >
       "$PYTHON" "$CI_PROJECT_DIR"/bind9-qa/ci/postprocess_junit_files.py "$CI_PROJECT_DIR/junit_doctest.xml" --output "$CI_PROJECT_DIR/junit.xml"
diff --git a/bin/tests/system/conftest.py b/bin/tests/system/conftest.py
index 3a05b72fe2..62e7bb6dd7 100644
--- a/bin/tests/system/conftest.py
+++ b/bin/tests/system/conftest.py
@@ -62,7 +62,6 @@ for _p in PRIORITY_TESTS:

 PRIORITY_TESTS_RE = Re("|".join(PRIORITY_TESTS))
 SYSTEM_TEST_NAME_RE = Re(f"{SYSTEM_TEST_DIR_GIT_PATH}" + r"/([^/]+)")
-SYMLINK_REPLACEMENT_RE = Re(r"/tests_(.*)\.py")

 # ---- Fix pytest-xdist loadscope for node IDs containing "::" ----------

@@ -285,12 +284,24 @@ def default_algorithm():


 @pytest.fixture(scope="module")
-def system_test_name(request):
+def system_test_source_dir(request):
     """
-    Name of the system test directory.
+    Directory holding the system test's files, as tracked in Git.
     """
-    path = Path(request.fspath)
-    return path.parent.name
+    return Path(request.fspath).parent.resolve()
+
+
+@pytest.fixture(scope="module")
+def system_test_name(system_test_source_dir):
+    """
+    Name of the system test.
+
+    For a test directory directly under bin/tests/system this is just its
+    name.  A test may also live deeper, next to the code it exercises
+    (isctest/asyncserver/tests); then the path components are joined with
+    underscores, which keeps the name usable as a directory and module name.
+    """
+    return "_".join(system_test_source_dir.relative_to(Path(FILE_DIR).resolve()).parts)


 @pytest.fixture(autouse=True)
@@ -395,7 +406,9 @@ def expected_artifacts(request):


 @pytest.fixture(scope="module")
-def system_test_dir(request, system_test_name, expected_artifacts):
+def system_test_dir(
+    request, system_test_name, system_test_source_dir, expected_artifacts
+):
     """
     Temporary directory for executing the test.

@@ -476,12 +489,12 @@ def system_test_dir(request, system_test_name, expected_artifacts):
         tempfile.mkdtemp(prefix=f"{system_test_name}-tmp-", dir=system_test_root)
     )
     shutil.rmtree(testdir)
-    shutil.copytree(system_test_root / system_test_name, testdir)
+    shutil.copytree(system_test_source_dir, testdir)
     isctest.vars.dirs.set_system_test_name(testdir.name)

     # Create a convenience symlink with a stable and predictable name
-    module_name = SYMLINK_REPLACEMENT_RE.sub(r"-\1", str(request.node.path))
-    symlink_dst = system_test_root / module_name
+    module_name = request.node.path.stem.removeprefix("tests_")
+    symlink_dst = system_test_root / f"{system_test_name}-{module_name}"
     symlink_dst.unlink(missing_ok=True)
     symlink_dst.symlink_to(os.path.relpath(testdir, start=system_test_root))

@@ -508,7 +521,7 @@ def system_test_dir(request, system_test_name, expected_artifacts):
         result = get_test_result()

         if result == "passed":
-            check_artifacts(system_test_root / system_test_name, testdir)
+            check_artifacts(system_test_source_dir, testdir)

         # Clean temporary dir unless it should be kept
         keep = False
diff --git a/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/ans.py b/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/ans.py
new file mode 120000
index 0000000000..0855b69d50
--- /dev/null
+++ b/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/ans.py
@@ -0,0 +1 @@
+../../../../../ans.py
\ No newline at end of file
diff --git a/bin/tests/system/selftest_asyncdnsserver/ans1/zones/example.db b/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/example.db
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/ans1/zones/example.db
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/example.db
diff --git a/bin/tests/system/selftest_asyncdnsserver/ans1/zones/nsec.test.db.j2.manual b/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/nsec.test.db.j2.manual
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/ans1/zones/nsec.test.db.j2.manual
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/nsec.test.db.j2.manual
diff --git a/bin/tests/system/selftest_asyncdnsserver/ans1/zones/nsec3.test.db.j2.manual b/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/nsec3.test.db.j2.manual
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/ans1/zones/nsec3.test.db.j2.manual
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/nsec3.test.db.j2.manual
diff --git a/bin/tests/system/selftest_asyncdnsserver/ans1/zones/optout.test.db.j2.manual b/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/optout.test.db.j2.manual
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/ans1/zones/optout.test.db.j2.manual
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/optout.test.db.j2.manual
diff --git a/bin/tests/system/selftest_asyncdnsserver/ans1/zones/salt.test.db.j2.manual b/bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/salt.test.db.j2.manual
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/ans1/zones/salt.test.db.j2.manual
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/ans1/zones/salt.test.db.j2.manual
diff --git a/bin/tests/system/selftest_asyncdnsserver/ns2/named.conf.j2 b/bin/tests/system/isctest/asyncserver/tests/dnssec/ns2/named.conf.j2
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/ns2/named.conf.j2
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/ns2/named.conf.j2
diff --git a/bin/tests/system/selftest_asyncdnsserver/tests_asyncserver_dnssec.py b/bin/tests/system/isctest/asyncserver/tests/dnssec/tests_asyncserver_dnssec.py
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/tests_asyncserver_dnssec.py
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/tests_asyncserver_dnssec.py
diff --git a/bin/tests/system/selftest_asyncdnsserver/tests_empty_non_terminal.py b/bin/tests/system/isctest/asyncserver/tests/dnssec/tests_empty_non_terminal.py
similarity index 100%
rename from bin/tests/system/selftest_asyncdnsserver/tests_empty_non_terminal.py
rename to bin/tests/system/isctest/asyncserver/tests/dnssec/tests_empty_non_terminal.py
diff --git a/bin/tests/system/selftest_asyncdnsserver/ans1/ans.py b/bin/tests/system/selftest_asyncdnsserver/ans1/ans.py
deleted file mode 120000
index 2416f57e65..0000000000
--- a/bin/tests/system/selftest_asyncdnsserver/ans1/ans.py
+++ /dev/null
@@ -1 +0,0 @@
-../../ans.py
\ No newline at end of file