import dns.message
import dns.name
import dns.query
+import dns.rcode
import dns.rrset
import pytest
tcp_round_trip(sock, msg)
+def wait_for_stable_tcp_requests(ns: NamedInstance, timeout: int = 10) -> int:
+ """Read the TCP request counter until it stops changing.
+
+ The counter is incremented on request receipt, so a client response
+ implies its upstream queries are already counted; this only needs to
+ absorb unsynchronized traffic such as the resolver's root priming query.
+ """
+ last = -1
+
+ def stable() -> bool:
+ nonlocal last
+ previous, last = last, tcp_requests_received(ns)
+ return previous == last
+
+ isctest.run.retry_with_timeout(stable, timeout=timeout)
+ return last
+
+
def test_tcp_request_statistics(
ns1: NamedInstance, ns2: NamedInstance, ns3: NamedInstance, ns4: NamedInstance
) -> None:
isctest.log.info("checking TCP request statistics (resolver)")
msg = isctest.query.create("txt.example.", "A")
- isctest.query.udp(msg, ns3.ip)
- time.sleep(1)
+ isctest.query.udp(msg, ns3.ip, expected_rcode=dns.rcode.NXDOMAIN)
- ns1_tcp_after_resolver = tcp_requests_received(ns1)
- ns2_tcp_after_resolver = tcp_requests_received(ns2)
+ ns1_tcp_after_resolver = wait_for_stable_tcp_requests(ns1)
+ ns2_tcp_after_resolver = wait_for_stable_tcp_requests(ns2)
assert ns1_tcp < ns1_tcp_after_resolver
assert ns2_tcp == ns2_tcp_after_resolver
isctest.log.info("checking TCP request statistics (forwarder)")
msg = isctest.query.create("txt.example.", "A")
- isctest.query.udp(msg, ns4.ip)
- time.sleep(1)
+ isctest.query.udp(msg, ns4.ip, expected_rcode=dns.rcode.NXDOMAIN)
- ns1_tcp_after_forwarder = tcp_requests_received(ns1)
- ns2_tcp_after_forwarder = tcp_requests_received(ns2)
+ ns1_tcp_after_forwarder = wait_for_stable_tcp_requests(ns1)
+ ns2_tcp_after_forwarder = wait_for_stable_tcp_requests(ns2)
assert ns1_tcp_after_resolver == ns1_tcp_after_forwarder
assert ns2_tcp_after_resolver < ns2_tcp_after_forwarder