]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Rework query functions to retry by default
authorMichal Nowak <mnowak@isc.org>
Tue, 16 Jul 2024 18:06:06 +0000 (20:06 +0200)
committerMichal Nowak <mnowak@isc.org>
Thu, 12 Sep 2024 09:42:22 +0000 (11:42 +0200)
bin/tests/system/dnstap/tests_dnstap.py
bin/tests/system/isctest/query.py
bin/tests/system/rpzextra/tests_rpzextra.py
bin/tests/system/shutdown/tests_shutdown.py
bin/tests/system/statschannel/generic.py

index 555435d8101975190b96fb4fdb6d48ddb443210f..2b2185a6f331c8713ac0385252fcf6e5762a1636 100644 (file)
@@ -39,7 +39,7 @@ def run_rndc(server, rndc_command):
 def test_dnstap_dispatch_socket_addresses():
     # Send some query to ns3 so that it records something in its dnstap file.
     msg = dns.message.make_query("mail.example.", "A")
-    res = isctest.query.tcp(msg, "10.53.0.2")
+    res = isctest.query.tcp(msg, "10.53.0.2", expected_rcode=dns.rcode.NOERROR)
     assert res.answer == [
         dns.rrset.from_text("mail.example.", 300, "IN", "A", "10.0.0.2")
     ]
index 46fd9b85f921a7edce933947fcab8f2ed249474e..c001e063d109d6f6f0ac9ab45f7788ff0ec13385 100644 (file)
 # information regarding copyright ownership.
 
 import os
-from typing import Optional
+import time
+from typing import Any, Callable, Optional
 
 import dns.query
 import dns.message
 
+import isctest.log
+
+# compatiblity with dnspython<2.0.0
+try:
+    # In dnspython>=2.0.0, dns.rcode.Rcode class is available
+    # pylint: disable=invalid-name
+    dns_rcode = dns.rcode.Rcode  # type: Any
+except AttributeError:
+    # In dnspython<2.0.0, selected rcodes are available as integers directly
+    # from dns.rcode
+    dns_rcode = dns.rcode
 
 QUERY_TIMEOUT = 10
 
 
-def udp(
+# pylint: disable=too-many-arguments
+def generic_query(
+    query_func: Callable[..., Any],
     message: dns.message.Message,
     ip: str,
     port: Optional[int] = None,
     source: Optional[str] = None,
     timeout: int = QUERY_TIMEOUT,
-) -> dns.message.Message:
+    attempts: int = 10,
+    expected_rcode: dns_rcode = None,
+) -> Any:
     if port is None:
         port = int(os.environ["PORT"])
-    return dns.query.udp(message, ip, timeout, port=port, source=source)
+    res = None
+    for attempt in range(attempts):
+        try:
+            isctest.log.debug(
+                f"{generic_query.__name__}(): ip={ip}, port={port}, source={source}, "
+                f"timeout={timeout}, attempts left={attempts-attempt}"
+            )
+            res = query_func(message, ip, timeout, port=port, source=source)
+            if res.rcode() == expected_rcode or expected_rcode is None:
+                return res
+        except (dns.exception.Timeout, ConnectionRefusedError) as e:
+            isctest.log.debug(f"{generic_query.__name__}(): the '{e}' exceptio raised")
+        time.sleep(1)
+    raise dns.exception.Timeout
 
 
-def tcp(
-    message: dns.message.Message,
-    ip: str,
-    port: Optional[int] = None,
-    source: Optional[str] = None,
-    timeout: int = QUERY_TIMEOUT,
-) -> dns.message.Message:
-    if port is None:
-        port = int(os.environ["PORT"])
-    return dns.query.tcp(message, ip, timeout, port=port, source=source)
+def udp(*args, **kwargs) -> Any:
+    return generic_query(dns.query.udp, *args, **kwargs)
+
+
+def tcp(*args, **kwargs) -> Any:
+    return generic_query(dns.query.tcp, *args, **kwargs)
index 25cd1f44f8c915d4384383cd8d658a41118faa64..5c2740ad637cacf997827c9d5dba88ac1c7af4d3 100644 (file)
@@ -20,20 +20,15 @@ import isctest
 import dns.message
 
 
-def wait_for_transfer(ip, port, client_ip, name, rrtype):
-    msg = dns.message.make_query(name, rrtype)
-    for _ in range(10):
-        try:
-            res = isctest.query.udp(msg, ip, source=client_ip)
-            if res.rcode() == dns.rcode.NOERROR:
-                break
-        except dns.exception.Timeout:
-            pass
-    else:
-        raise RuntimeError(
-            "zone transfer failed: "
-            f"client: {client_ip}, name: {name}, rrtype: {rrtype} from @{ip}:{port}"
-        )
+# compatiblity with dnspython<2.0.0
+try:
+    # In dnspython>=2.0.0, dns.rcode.Rcode class is available
+    # pylint: disable=invalid-name
+    dns_rcode = dns.rcode.Rcode  # type: Any
+except AttributeError:
+    # In dnspython<2.0.0, selected rcodes are available as integers directly
+    # from dns.rcode
+    dns_rcode = dns.rcode
 
 
 @pytest.mark.parametrize(
@@ -76,13 +71,24 @@ def wait_for_transfer(ip, port, client_ip, name, rrtype):
         ("allowed.", "10.53.0.5", dns.rcode.NXDOMAIN),
     ],
 )
-def test_rpz_multiple_views(qname, source, rcode, named_port):
-    wait_for_transfer("10.53.0.3", named_port, "10.53.0.2", "rpz-external.local", "SOA")
-    wait_for_transfer("10.53.0.3", named_port, "10.53.0.5", "rpz-external.local", "SOA")
+def test_rpz_multiple_views(qname, source, rcode):
+    # Wait for the rpz-external.local zone transfer
+    msg = dns.message.make_query("rpz-external.local", "SOA")
+    isctest.query.tcp(
+        msg,
+        ip="10.53.0.3",
+        source="10.53.0.2",
+        expected_rcode=dns_rcode.NOERROR,
+    )
+    isctest.query.tcp(
+        msg,
+        ip="10.53.0.3",
+        source="10.53.0.5",
+        expected_rcode=dns_rcode.NOERROR,
+    )
 
     msg = dns.message.make_query(qname, "A")
-    res = isctest.query.udp(msg, "10.53.0.3", source=source)
-    assert res.rcode() == rcode
+    res = isctest.query.udp(msg, "10.53.0.3", source=source, expected_rcode=rcode)
     if rcode == dns.rcode.NOERROR:
         assert res.answer == [dns.rrset.from_text(qname, 300, "IN", "A", "10.53.0.2")]
 
@@ -92,7 +98,9 @@ def test_rpz_passthru_logging():
 
     # Should generate a log entry into rpz_passthru.txt
     msg_allowed = dns.message.make_query("allowed.", "A")
-    res_allowed = isctest.query.udp(msg_allowed, resolver_ip, source="10.53.0.1")
+    res_allowed = isctest.query.udp(
+        msg_allowed, resolver_ip, source="10.53.0.1", expected_rcode=dns.rcode.NOERROR
+    )
     assert res_allowed.answer == [
         dns.rrset.from_text("allowed.", 300, "IN", "A", "10.53.0.2")
     ]
@@ -101,7 +109,10 @@ def test_rpz_passthru_logging():
     # Should generate a log entry into rpz.txt
     msg_not_allowed = dns.message.make_query("baddomain.", "A")
     res_not_allowed = isctest.query.udp(
-        msg_not_allowed, resolver_ip, source="10.53.0.1"
+        msg_not_allowed,
+        resolver_ip,
+        source="10.53.0.1",
+        expected_rcode=dns.rcode.NXDOMAIN,
     )
     isctest.check.nxdomain(res_not_allowed)
 
index 3b64389a627a66ffc5902e515a5f8dcd69d7d36b..0fc2b1c5e9189e9f09333a7a1646f90d93f41418 100755 (executable)
@@ -132,18 +132,6 @@ def do_work(named_proc, resolver_ip, instance, kill_method, n_workers, n_queries
             assert ret_code == 0
 
 
-def wait_for_named_loaded(resolver_ip, retries=10):
-    msg = dns.message.make_query("version.bind", "TXT", "CH")
-    for _ in range(retries):
-        try:
-            res = isctest.query.udp(msg, resolver_ip)
-            if res.rcode() == dns.rcode.NOERROR:
-                return True
-        except dns.exception.Timeout:
-            time.sleep(1)
-    return False
-
-
 def wait_for_proc_termination(proc, max_timeout=10):
     for _ in range(max_timeout):
         if proc.poll() is not None:
@@ -194,7 +182,9 @@ def test_named_shutdown(kill_method):
         ) as named_proc:
             try:
                 assert named_proc.poll() is None, "named isn't running"
-                assert wait_for_named_loaded(resolver_ip)
+                msg = dns.message.make_query("version.bind", "TXT", "CH")
+                res = isctest.query.tcp(msg, resolver_ip)
+                isctest.check.noerror(res)
                 do_work(
                     named_proc,
                     resolver_ip,
index f4b3d857e8077664342627d5f363c0688803b2a0..611d396925793e5c5f29fcde4d3212d971722638 100644 (file)
@@ -194,7 +194,7 @@ def test_traffic(fetch_traffic, **kwargs):
 
     msg = create_msg("short.example.", "TXT")
     update_expected(exp, "dns-udp-requests-sizes-received-ipv4", msg)
-    ans = isctest.query.udp(msg, statsip)
+    ans = isctest.query.udp(msg, statsip, attempts=1)
     isctest.check.noerror(ans)
     update_expected(exp, "dns-udp-responses-sizes-sent-ipv4", ans)
     data = fetch_traffic(statsip, statsport)
@@ -203,7 +203,7 @@ def test_traffic(fetch_traffic, **kwargs):
 
     msg = create_msg("long.example.", "TXT")
     update_expected(exp, "dns-udp-requests-sizes-received-ipv4", msg)
-    ans = isctest.query.udp(msg, statsip)
+    ans = isctest.query.udp(msg, statsip, attempts=1)
     isctest.check.noerror(ans)
     update_expected(exp, "dns-udp-responses-sizes-sent-ipv4", ans)
     data = fetch_traffic(statsip, statsport)
@@ -212,7 +212,7 @@ def test_traffic(fetch_traffic, **kwargs):
 
     msg = create_msg("short.example.", "TXT")
     update_expected(exp, "dns-tcp-requests-sizes-received-ipv4", msg)
-    ans = isctest.query.tcp(msg, statsip)
+    ans = isctest.query.tcp(msg, statsip, attempts=1)
     isctest.check.noerror(ans)
     update_expected(exp, "dns-tcp-responses-sizes-sent-ipv4", ans)
     data = fetch_traffic(statsip, statsport)
@@ -221,7 +221,7 @@ def test_traffic(fetch_traffic, **kwargs):
 
     msg = create_msg("long.example.", "TXT")
     update_expected(exp, "dns-tcp-requests-sizes-received-ipv4", msg)
-    ans = isctest.query.tcp(msg, statsip)
+    ans = isctest.query.tcp(msg, statsip, attempts=1)
     isctest.check.noerror(ans)
     update_expected(exp, "dns-tcp-responses-sizes-sent-ipv4", ans)
     data = fetch_traffic(statsip, statsport)