From ba9b33e63a18841cdb7cf5f912d99ccbea91dee4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 10 Oct 2024 09:35:22 -0500 Subject: [PATCH] [PR #9451/216e082 backport][3.10] Fix AsyncResolver swallowing the error message (#9452) --- CHANGES/9451.bugfix.rst | 1 + aiohttp/resolver.py | 4 ++-- tests/test_resolver.py | 30 +++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 CHANGES/9451.bugfix.rst diff --git a/CHANGES/9451.bugfix.rst b/CHANGES/9451.bugfix.rst new file mode 100644 index 00000000000..2adcbc66273 --- /dev/null +++ b/CHANGES/9451.bugfix.rst @@ -0,0 +1 @@ +Fixed error messages from :py:class:`~aiohttp.resolver.AsyncResolver` being swallowed -- by :user:`bdraco`. diff --git a/aiohttp/resolver.py b/aiohttp/resolver.py index 6283ec2b8d5..385ae21abf5 100644 --- a/aiohttp/resolver.py +++ b/aiohttp/resolver.py @@ -111,7 +111,7 @@ async def resolve( ) except aiodns.error.DNSError as exc: msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" - raise OSError(msg) from exc + raise OSError(None, msg) from exc hosts: List[ResolveResult] = [] for node in resp.nodes: address: Union[Tuple[bytes, int], Tuple[bytes, int, int, int]] = node.addr @@ -145,7 +145,7 @@ async def resolve( ) if not hosts: - raise OSError("DNS lookup failed") + raise OSError(None, "DNS lookup failed") return hosts diff --git a/tests/test_resolver.py b/tests/test_resolver.py index 8b2ea620037..6322bcfca64 100644 --- a/tests/test_resolver.py +++ b/tests/test_resolver.py @@ -339,7 +339,35 @@ async def test_async_resolver_query_ipv6_positive_lookup(loop) -> None: mock().query.assert_called_with("www.python.org", "AAAA") -async def test_async_resolver_aiodns_not_present(loop, monkeypatch) -> None: +@pytest.mark.skipif(not getaddrinfo, reason="aiodns >=3.2.0 required") +async def test_async_resolver_error_messages_passed( + loop: asyncio.AbstractEventLoop, +) -> None: + """Ensure error messages are passed through from aiodns.""" + with patch("aiodns.DNSResolver", autospec=True, spec_set=True) as mock: + mock().getaddrinfo.side_effect = aiodns.error.DNSError(1, "Test error message") + resolver = AsyncResolver() + with pytest.raises(OSError, match="Test error message") as excinfo: + await resolver.resolve("x.org") + + assert excinfo.value.strerror == "Test error message" + + +@pytest.mark.skipif(not getaddrinfo, reason="aiodns >=3.2.0 required") +async def test_async_resolver_error_messages_passed_no_hosts( + loop: asyncio.AbstractEventLoop, +) -> None: + """Ensure error messages are passed through from aiodns.""" + with patch("aiodns.DNSResolver", autospec=True, spec_set=True) as mock: + mock().getaddrinfo.return_value = fake_aiodns_getaddrinfo_ipv6_result([]) + resolver = AsyncResolver() + with pytest.raises(OSError, match="DNS lookup failed") as excinfo: + await resolver.resolve("x.org") + + assert excinfo.value.strerror == "DNS lookup failed" + + +async def test_async_resolver_aiodns_not_present(loop: Any, monkeypatch: Any) -> None: monkeypatch.setattr("aiohttp.resolver.aiodns", None) with pytest.raises(RuntimeError): AsyncResolver(loop=loop)