mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-13 14:49:59 -04:00
[9.20] fix: test: Require dnspython>2.0.0 in system tests using asyncserver
Maintaining compatibility with pre-2.0.0 dnspython became cumbersome leading to failure in nightly CI jobs which are the only ones that run with dnspython this old. Abort all AsyncServer instances when running with old dnspython. Add an importor skip for all system tests using isctest.asyncserver. Full removal of pre-2.0.0 `dnspython` support is planned for after 9.18 goes EoL. Backport of MR !11191 Merge branch 'backport-stepan/require-dnspython-2-for-asyncserver-9.20' into 'bind-9.20' See merge request isc-projects/bind9!11209
This commit is contained in:
commit
3a41fbcdde
21 changed files with 91 additions and 35 deletions
|
|
@ -1020,7 +1020,6 @@ gcc:almalinux8:amd64:
|
|||
system:gcc:almalinux8:amd64:
|
||||
<<: *almalinux_8_amd64_image
|
||||
<<: *system_test_job
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
needs:
|
||||
- job: gcc:almalinux8:amd64
|
||||
artifacts: true
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out.*",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out.*",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
import pytest
|
||||
import isctest
|
||||
|
||||
pytest.importorskip("dns")
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
import dns.message
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
".hypothesis/examples/*",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out.*",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out.*",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
# information regarding copyright ownership.
|
||||
|
||||
import isctest
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
|
||||
def test_async_hook():
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ class AsyncServer:
|
|||
tcp_handler: Optional[_TcpHandler],
|
||||
pidfile: Optional[str] = None,
|
||||
) -> None:
|
||||
self._abort_if_on_dnspython_version_less_than_2_0_0()
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s %(levelname)8s %(message)s",
|
||||
level=os.environ.get("ANS_LOG_LEVEL", "INFO").upper(),
|
||||
|
|
@ -143,6 +144,14 @@ class AsyncServer:
|
|||
self._pidfile: Optional[str] = pidfile
|
||||
self._work_done: Optional[asyncio.Future] = None
|
||||
|
||||
@classmethod
|
||||
def _abort_if_on_dnspython_version_less_than_2_0_0(cls) -> None:
|
||||
if dns.version.MAJOR < 2:
|
||||
error = f"Using {cls.__name__} requires dnspython >= 2.0.0; "
|
||||
error += 'add `pytest.importorskip("dns", minversion="2.0.0")` '
|
||||
error += "to the test module to skip this test."
|
||||
raise RuntimeError(error)
|
||||
|
||||
def _get_ipv4_address_from_directory_name(self) -> str:
|
||||
containing_directory = pathlib.Path().absolute().stem
|
||||
match_result = re.match(r"ans(?P<index>\d+)", containing_directory)
|
||||
|
|
@ -1053,7 +1062,6 @@ class AsyncDnsServer(AsyncServer):
|
|||
try:
|
||||
query = dns.message.from_wire(wire)
|
||||
except dns.message.UnknownTSIGKey:
|
||||
self._abort_if_on_dnspython_version_less_than_2_0_0()
|
||||
self._abort_if_tsig_signed_query_received_unless_acknowledged()
|
||||
query = _DnsMessageWithTsigDisabled.from_wire(wire)
|
||||
except dns.exception.DNSException as exc:
|
||||
|
|
@ -1074,13 +1082,6 @@ class AsyncDnsServer(AsyncServer):
|
|||
response_length = struct.pack("!H", len(response))
|
||||
yield response_length + response
|
||||
|
||||
def _abort_if_on_dnspython_version_less_than_2_0_0(self) -> None:
|
||||
if dns.version.MAJOR < 2:
|
||||
error = "Receiving TSIG signed queries requires dnspython >= 2.0.0; "
|
||||
error += 'add `pytest.importorskip("dns", minversion="2.0.0")` '
|
||||
error += "to the test module to skip this test."
|
||||
raise RuntimeError(error)
|
||||
|
||||
def _abort_if_tsig_signed_query_received_unless_acknowledged(self) -> None:
|
||||
if self._acknowledge_tsig_dnspython_hacks:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -9,15 +9,14 @@
|
|||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from typing import Container, Iterable, FrozenSet
|
||||
from typing import Iterable, FrozenSet
|
||||
|
||||
import pytest
|
||||
|
||||
pytest.importorskip("dns", minversion="2.3.0") # NameRelation
|
||||
from dns.name import Name, NameRelation
|
||||
import dns.name
|
||||
import dns.zone
|
||||
import dns.rdatatype
|
||||
|
||||
from dns.name import Name
|
||||
|
||||
|
||||
def prepend_label(label: str, name: Name) -> Name:
|
||||
return Name((label,) + name.labels)
|
||||
|
|
@ -60,6 +59,7 @@ class ZoneAnalyzer:
|
|||
return cls(zonedb)
|
||||
|
||||
def __init__(self, zone: dns.zone.Zone):
|
||||
self._abort_on_old_dnspython()
|
||||
self.zone = zone
|
||||
assert self.zone.origin # mypy hack
|
||||
# based on individual nodes but not relationship between nodes
|
||||
|
|
@ -85,6 +85,14 @@ class ZoneAnalyzer:
|
|||
.union(self.reachable_dnames)
|
||||
)
|
||||
|
||||
def _abort_on_old_dnspython(self):
|
||||
if not hasattr(dns.name, "NameRelation"):
|
||||
raise RuntimeError(
|
||||
"ZoneAnalyzer requires dnspython>=2.3.0 for dns.name.NameRelation support. "
|
||||
"Use pytest.importorskip('dns', minversion='2.3.0') to the test module to "
|
||||
"skip this test."
|
||||
)
|
||||
|
||||
def get_names_with_type(self, rdtype) -> FrozenSet[Name]:
|
||||
return frozenset(
|
||||
name for name in self.zone if self.zone.get_rdataset(name, rdtype)
|
||||
|
|
@ -117,15 +125,15 @@ class ZoneAnalyzer:
|
|||
for name in reachable:
|
||||
relation, _, _ = name.fullcompare(self.zone.origin)
|
||||
if relation in (
|
||||
NameRelation.NONE, # out of zone?
|
||||
NameRelation.SUPERDOMAIN, # parent of apex?!
|
||||
dns.name.NameRelation.NONE, # out of zone?
|
||||
dns.name.NameRelation.SUPERDOMAIN, # parent of apex?!
|
||||
):
|
||||
raise NotImplementedError
|
||||
|
||||
for maybe_occluded in reachable.copy():
|
||||
for cut in self.delegations:
|
||||
rel, _, _ = maybe_occluded.fullcompare(cut)
|
||||
if rel == NameRelation.EQUAL:
|
||||
if rel == dns.name.NameRelation.EQUAL:
|
||||
# data _on_ a parent-side of a zone cut are in limbo:
|
||||
# - are not really authoritative (except for DS)
|
||||
# - but NS is not really 'occluded'
|
||||
|
|
@ -134,14 +142,14 @@ class ZoneAnalyzer:
|
|||
if maybe_occluded in reachable:
|
||||
reachable.remove(maybe_occluded)
|
||||
|
||||
if rel == NameRelation.SUBDOMAIN:
|
||||
if rel == dns.name.NameRelation.SUBDOMAIN:
|
||||
_mark_occluded(maybe_occluded)
|
||||
# do not break cycle - handle also nested NS and DNAME
|
||||
|
||||
# DNAME itself is authoritative but nothing under it is reachable
|
||||
for dname in self.dnames:
|
||||
rel, _, _ = maybe_occluded.fullcompare(dname)
|
||||
if rel == NameRelation.SUBDOMAIN:
|
||||
if rel == dns.name.NameRelation.SUBDOMAIN:
|
||||
_mark_occluded(maybe_occluded)
|
||||
# do not break cycle - handle also nested NS and DNAME
|
||||
|
||||
|
|
@ -174,7 +182,7 @@ class ZoneAnalyzer:
|
|||
nce = None # Next closer name, RFC 5155
|
||||
for zname in self.all_existing_names:
|
||||
relation, _, common_labels = qname.fullcompare(zname)
|
||||
if relation == NameRelation.SUBDOMAIN:
|
||||
if relation == dns.name.NameRelation.SUBDOMAIN:
|
||||
if not ce or common_labels > len(ce):
|
||||
# longest match so far
|
||||
ce = zname
|
||||
|
|
@ -190,15 +198,3 @@ class ZoneAnalyzer:
|
|||
"""
|
||||
ce, _ = self.closest_encloser(qname)
|
||||
return Name("*") + ce
|
||||
|
||||
|
||||
def is_related_to_any(
|
||||
test_name: Name,
|
||||
acceptable_relations: Container[NameRelation],
|
||||
candidates: Iterable[Name],
|
||||
) -> bool:
|
||||
for maybe_parent in candidates:
|
||||
relation, _, _ = test_name.fullcompare(maybe_parent)
|
||||
if relation in acceptable_relations:
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
from dataclasses import dataclass
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional, Set, Tuple
|
||||
from typing import Container, Iterable, Optional, Set, Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -45,6 +45,18 @@ ZONE = isctest.name.ZoneAnalyzer.read_path(
|
|||
)
|
||||
|
||||
|
||||
def is_related_to_any(
|
||||
test_name: dns.name.Name,
|
||||
acceptable_relations: Container[dns.name.NameRelation],
|
||||
candidates: Iterable[dns.name.Name],
|
||||
) -> bool:
|
||||
for maybe_parent in candidates:
|
||||
relation, _, _ = test_name.fullcompare(maybe_parent)
|
||||
if relation in acceptable_relations:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def do_test_query(
|
||||
qname: dns.name.Name, qtype: dns.rdatatype.RdataType, server: str, named_port: int
|
||||
) -> Tuple[dns.message.QueryMessage, "NSEC3Checker"]:
|
||||
|
|
@ -103,7 +115,7 @@ def assume_nx_and_no_delegation(qname: dns.name.Name) -> None:
|
|||
# name must not be under a delegation or DNAME:
|
||||
# it would not work with resolver ns2
|
||||
assume(
|
||||
not isctest.name.is_related_to_any(
|
||||
not is_related_to_any(
|
||||
qname,
|
||||
(dns.name.NameRelation.EQUAL, dns.name.NameRelation.SUBDOMAIN),
|
||||
ZONE.reachable_delegations.union(ZONE.reachable_dnames),
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ import platform
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"Kxxx*",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out.*",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out.*",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
import isctest.mark
|
||||
|
||||
pytestmark = [
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import pytest
|
|||
import isctest
|
||||
import isctest.name
|
||||
|
||||
pytest.importorskip("dns.name", minversion="2.3.0")
|
||||
|
||||
# set of properies present in the tested zone - read by tests_zone_analyzer.py
|
||||
CATEGORIES = frozenset(
|
||||
[
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"curl.out.*",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ import time
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
import dns.message
|
||||
import dns.query
|
||||
import dns.tsigkeyring
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"axfr.out",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out*",
|
||||
|
|
|
|||
Loading…
Reference in a new issue