Fix unawaited coroutine test warnings
This commit is contained in:
parent
e268794564
commit
6ce1d7da2f
2 changed files with 75 additions and 46 deletions
|
|
@ -28,3 +28,9 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["src/hosts"]
|
packages = ["src/hosts"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
filterwarnings = [
|
||||||
|
"error:coroutine .* was never awaited:RuntimeWarning",
|
||||||
|
"error::pytest.PytestUnraisableExceptionWarning",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ and integration with hosts entries.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import asyncio
|
import asyncio
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
|
@ -94,72 +94,83 @@ class TestResolveHostname:
|
||||||
async def test_successful_resolution(self):
|
async def test_successful_resolution(self):
|
||||||
"""Test successful hostname resolution."""
|
"""Test successful hostname resolution."""
|
||||||
with patch("asyncio.get_event_loop") as mock_loop:
|
with patch("asyncio.get_event_loop") as mock_loop:
|
||||||
mock_event_loop = AsyncMock()
|
mock_event_loop = MagicMock()
|
||||||
mock_loop.return_value = mock_event_loop
|
mock_loop.return_value = mock_event_loop
|
||||||
|
|
||||||
# Mock successful getaddrinfo result
|
# Mock successful getaddrinfo result
|
||||||
mock_result = [
|
mock_result = [
|
||||||
(socket.AF_INET, socket.SOCK_STREAM, 6, "", ("192.0.2.1", 80))
|
(socket.AF_INET, socket.SOCK_STREAM, 6, "", ("192.0.2.1", 80))
|
||||||
]
|
]
|
||||||
mock_event_loop.getaddrinfo.return_value = mock_result
|
mock_event_loop.getaddrinfo = AsyncMock(return_value=mock_result)
|
||||||
|
|
||||||
with patch("asyncio.wait_for", return_value=mock_result):
|
resolution = await resolve_hostname("example.com")
|
||||||
resolution = await resolve_hostname("example.com")
|
|
||||||
|
|
||||||
assert resolution.hostname == "example.com"
|
assert resolution.hostname == "example.com"
|
||||||
assert resolution.resolved_ip == "192.0.2.1"
|
assert resolution.resolved_ip == "192.0.2.1"
|
||||||
assert resolution.status == DNSResolutionStatus.RESOLVED
|
assert resolution.status == DNSResolutionStatus.RESOLVED
|
||||||
assert resolution.error_message is None
|
assert resolution.error_message is None
|
||||||
assert resolution.is_success() is True
|
assert resolution.is_success() is True
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_timeout_resolution(self):
|
async def test_timeout_resolution(self):
|
||||||
"""Test hostname resolution timeout."""
|
"""Test hostname resolution timeout."""
|
||||||
|
|
||||||
async def mock_wait_for(*args, **kwargs):
|
async def mock_wait_for(awaitable, **kwargs):
|
||||||
|
await awaitable
|
||||||
raise asyncio.TimeoutError()
|
raise asyncio.TimeoutError()
|
||||||
|
|
||||||
with patch("asyncio.wait_for", side_effect=mock_wait_for) as mock_wait_for:
|
with patch("asyncio.get_event_loop") as mock_loop:
|
||||||
resolution = await resolve_hostname("slow.example", timeout=1.0)
|
mock_event_loop = MagicMock()
|
||||||
|
mock_loop.return_value = mock_event_loop
|
||||||
|
mock_event_loop.getaddrinfo = AsyncMock(return_value=[])
|
||||||
|
|
||||||
assert resolution.hostname == "slow.example"
|
with patch("asyncio.wait_for", side_effect=mock_wait_for):
|
||||||
assert resolution.resolved_ip is None
|
resolution = await resolve_hostname("slow.example", timeout=1.0)
|
||||||
assert resolution.status == DNSResolutionStatus.RESOLUTION_FAILED
|
|
||||||
assert resolution.error_message is not None
|
assert resolution.hostname == "slow.example"
|
||||||
assert "Timeout after 1.0s" in resolution.error_message
|
assert resolution.resolved_ip is None
|
||||||
assert resolution.is_success() is False
|
assert resolution.status == DNSResolutionStatus.RESOLUTION_FAILED
|
||||||
|
assert resolution.error_message is not None
|
||||||
|
assert "Timeout after 1.0s" in resolution.error_message
|
||||||
|
assert resolution.is_success() is False
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_dns_error_resolution(self):
|
async def test_dns_error_resolution(self):
|
||||||
"""Test hostname resolution with DNS error."""
|
"""Test hostname resolution with DNS error."""
|
||||||
with patch("asyncio.wait_for", side_effect=socket.gaierror("Name not found")):
|
|
||||||
resolution = await resolve_hostname("nonexistent.example")
|
|
||||||
|
|
||||||
assert resolution.hostname == "nonexistent.example"
|
async def mock_wait_for(awaitable, **kwargs):
|
||||||
assert resolution.resolved_ip is None
|
await awaitable
|
||||||
assert resolution.status == DNSResolutionStatus.RESOLUTION_FAILED
|
raise socket.gaierror("Name not found")
|
||||||
assert resolution.error_message == "Name not found"
|
|
||||||
assert resolution.is_success() is False
|
with patch("asyncio.get_event_loop") as mock_loop:
|
||||||
|
mock_event_loop = MagicMock()
|
||||||
|
mock_loop.return_value = mock_event_loop
|
||||||
|
mock_event_loop.getaddrinfo = AsyncMock(return_value=[])
|
||||||
|
|
||||||
|
with patch("asyncio.wait_for", side_effect=mock_wait_for):
|
||||||
|
resolution = await resolve_hostname("nonexistent.example")
|
||||||
|
|
||||||
|
assert resolution.hostname == "nonexistent.example"
|
||||||
|
assert resolution.resolved_ip is None
|
||||||
|
assert resolution.status == DNSResolutionStatus.RESOLUTION_FAILED
|
||||||
|
assert resolution.error_message == "Name not found"
|
||||||
|
assert resolution.is_success() is False
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_empty_result_resolution(self):
|
async def test_empty_result_resolution(self):
|
||||||
"""Test hostname resolution with empty result."""
|
"""Test hostname resolution with empty result."""
|
||||||
|
|
||||||
async def mock_wait_for(*args, **kwargs):
|
|
||||||
return []
|
|
||||||
|
|
||||||
with patch("asyncio.get_event_loop") as mock_loop:
|
with patch("asyncio.get_event_loop") as mock_loop:
|
||||||
mock_event_loop = AsyncMock()
|
mock_event_loop = MagicMock()
|
||||||
mock_loop.return_value = mock_event_loop
|
mock_loop.return_value = mock_event_loop
|
||||||
|
mock_event_loop.getaddrinfo = AsyncMock(return_value=[])
|
||||||
|
|
||||||
with patch("asyncio.wait_for", side_effect=mock_wait_for):
|
resolution = await resolve_hostname("empty.example")
|
||||||
resolution = await resolve_hostname("empty.example")
|
|
||||||
|
|
||||||
assert resolution.hostname == "empty.example"
|
assert resolution.hostname == "empty.example"
|
||||||
assert resolution.resolved_ip is None
|
assert resolution.resolved_ip is None
|
||||||
assert resolution.status == DNSResolutionStatus.RESOLUTION_FAILED
|
assert resolution.status == DNSResolutionStatus.RESOLUTION_FAILED
|
||||||
assert resolution.error_message == "No address found"
|
assert resolution.error_message == "No address found"
|
||||||
assert resolution.is_success() is False
|
assert resolution.is_success() is False
|
||||||
|
|
||||||
|
|
||||||
class TestResolveHostnamesBatch:
|
class TestResolveHostnamesBatch:
|
||||||
|
|
@ -240,6 +251,8 @@ class TestResolveHostnamesBatch:
|
||||||
|
|
||||||
# Create a mock that returns the expected results
|
# Create a mock that returns the expected results
|
||||||
async def mock_gather(*tasks, return_exceptions=True):
|
async def mock_gather(*tasks, return_exceptions=True):
|
||||||
|
for task in tasks:
|
||||||
|
await task
|
||||||
return [
|
return [
|
||||||
DNSResolution(
|
DNSResolution(
|
||||||
hostname="example.com",
|
hostname="example.com",
|
||||||
|
|
@ -250,15 +263,25 @@ class TestResolveHostnamesBatch:
|
||||||
Exception("Network error"),
|
Exception("Network error"),
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch("asyncio.gather", side_effect=mock_gather):
|
with patch(
|
||||||
resolutions = await resolve_hostnames_batch(hostnames)
|
"src.hosts.core.dns.resolve_hostname",
|
||||||
|
new_callable=AsyncMock,
|
||||||
|
) as mock_resolve:
|
||||||
|
mock_resolve.return_value = DNSResolution(
|
||||||
|
hostname="ignored.example",
|
||||||
|
resolved_ip=None,
|
||||||
|
status=DNSResolutionStatus.RESOLUTION_FAILED,
|
||||||
|
resolved_at=datetime.now(),
|
||||||
|
)
|
||||||
|
with patch("asyncio.gather", side_effect=mock_gather):
|
||||||
|
resolutions = await resolve_hostnames_batch(hostnames)
|
||||||
|
|
||||||
assert len(resolutions) == 2
|
assert len(resolutions) == 2
|
||||||
assert resolutions[0].is_success() is True
|
assert resolutions[0].is_success() is True
|
||||||
assert resolutions[1].hostname == "error.example"
|
assert resolutions[1].hostname == "error.example"
|
||||||
assert resolutions[1].is_success() is False
|
assert resolutions[1].is_success() is False
|
||||||
assert resolutions[1].error_message is not None
|
assert resolutions[1].error_message is not None
|
||||||
assert "Network error" in resolutions[1].error_message
|
assert "Network error" in resolutions[1].error_message
|
||||||
|
|
||||||
|
|
||||||
class TestDNSService:
|
class TestDNSService:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue