Skip to content

Commit 7b89c2e

Browse files
committed
Refactor test_dns_server_udp_handler.py
1 parent c40e60c commit 7b89c2e

1 file changed

Lines changed: 26 additions & 57 deletions

File tree

tests/indisoluble/a_healthy_dns/test_dns_server_udp_handler.py

Lines changed: 26 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@
2020
from indisoluble.a_healthy_dns.records.zone_origins import ZoneOrigins
2121

2222

23+
def _make_multi_question_wire(*question_names):
24+
queries = [
25+
dns.message.make_query(question_name, dns.rdatatype.A)
26+
for question_name in question_names
27+
]
28+
wire = bytearray(queries[0].to_wire())
29+
wire[4:6] = len(queries).to_bytes(2)
30+
31+
for query in queries[1:]:
32+
wire.extend(query.to_wire()[12:])
33+
34+
return bytes(wire)
35+
36+
2337
@pytest.fixture
2438
def mock_reader():
2539
reader = MagicMock(spec=dns.zone.Transaction)
@@ -75,7 +89,6 @@ def mock_soa_rdataset(mock_soa_rdata):
7589
return mock_soa_rdataset
7690

7791

78-
7992
@pytest.fixture
8093
def mock_server(mock_zone, mock_zone_origins):
8194
server = MagicMock()
@@ -286,11 +299,7 @@ def test_handle_exception_parsing_query(
286299
mock_from_wire.side_effect = dns.exception.DNSException("Test exception")
287300

288301
# No need to call handle() as it's called automatically by the constructor
289-
with patch("logging.warning") as mock_logging:
290-
_ = DnsServerUdpHandler(dns_request, dns_client_address, mock_server)
291-
292-
mock_logging.assert_called_once()
293-
assert "Failed to parse DNS query" in mock_logging.call_args[0][0]
302+
_ = DnsServerUdpHandler(dns_request, dns_client_address, mock_server)
294303

295304
# Assertions
296305
query_data = dns_request[0]
@@ -302,64 +311,24 @@ def test_handle_exception_parsing_query(
302311

303312

304313
@patch("indisoluble.a_healthy_dns.dns_server_udp_handler._update_response")
305-
def test_handle_query_without_question(
306-
mock_update_response, dns_client_address, mock_server
314+
@pytest.mark.parametrize(
315+
"query_data",
316+
[
317+
dns.message.Message().to_wire(),
318+
_make_multi_question_wire("example.com.", "test.com."),
319+
],
320+
)
321+
def test_handle_query_with_invalid_question_count_returns_formerr(
322+
mock_update_response, query_data, dns_client_address, mock_server
307323
):
308-
# Create a request with an empty question section
309-
query = dns.message.Message()
310324
mock_sock = MagicMock()
311-
request = (query.to_wire(), mock_sock)
312-
313-
# No need to call handle() as it's called automatically by the constructor
314-
with patch("logging.warning") as mock_logging:
315-
_ = DnsServerUdpHandler(request, dns_client_address, mock_server)
325+
request = (query_data, mock_sock)
316326

317-
mock_logging.assert_called_once()
318-
assert "0 questions, expected exactly 1" in (
319-
mock_logging.call_args[0][0] % mock_logging.call_args[0][1]
320-
)
327+
_ = DnsServerUdpHandler(request, dns_client_address, mock_server)
321328

322-
# Assertions
323329
mock_update_response.assert_not_called()
324-
325-
# Check response was sent with FORMERR
326330
mock_sock.sendto.assert_called_once()
327331

328332
sent_data = mock_sock.sendto.call_args[0][0]
329333
response = dns.message.from_wire(sent_data)
330334
assert response.rcode() == dns.rcode.FORMERR
331-
332-
333-
@patch("indisoluble.a_healthy_dns.dns_server_udp_handler._update_response")
334-
def test_handle_query_with_multiple_questions(
335-
mock_update_response, dns_client_address, mock_server
336-
):
337-
# Build a wire message with QDCOUNT=2 by crafting the bytes directly:
338-
# start from a valid single-question query, patch QDCOUNT to 2, then
339-
# append the question bytes from a second query.
340-
q1 = dns.message.make_query("example.com.", dns.rdatatype.A)
341-
wire = bytearray(q1.to_wire())
342-
# QDCOUNT is at bytes 4-5 of the DNS header
343-
wire[4] = 0
344-
wire[5] = 2
345-
q2 = dns.message.make_query("test.com.", dns.rdatatype.A)
346-
# Append the question section of q2 (everything after the 12-byte header)
347-
wire.extend(q2.to_wire()[12:])
348-
349-
mock_sock = MagicMock()
350-
request = (bytes(wire), mock_sock)
351-
352-
with patch("logging.warning") as mock_logging:
353-
_ = DnsServerUdpHandler(request, dns_client_address, mock_server)
354-
355-
mock_logging.assert_called_once()
356-
assert "2 questions, expected exactly 1" in (
357-
mock_logging.call_args[0][0] % mock_logging.call_args[0][1]
358-
)
359-
360-
mock_update_response.assert_not_called()
361-
362-
mock_sock.sendto.assert_called_once()
363-
sent_data = mock_sock.sendto.call_args[0][0]
364-
response = dns.message.from_wire(sent_data)
365-
assert response.rcode() == dns.rcode.FORMERR

0 commit comments

Comments
 (0)