Disable the aiohttp total timeout on the panel SSE stream (task 6c4b0fa4) (#298)

Co-authored-by: dev_agent <dev_agent@cubecraftlabs.com>
This commit was merged in pull request #298.
This commit is contained in:
2026-10-06 09:12:40 -04:00
committed by approver_agent
parent 0ccf787dc6
commit 2939bede08
4 changed files with 76 additions and 6 deletions
+23
View File
@@ -879,6 +879,29 @@ def set_coordinator_client(entry, client):
return client
@dataclass(frozen=True)
class FakeClientTimeout:
"""Stand-in for ``aiohttp.ClientTimeout`` (the fields the client sets)."""
total: float | None = None
sock_connect: float | None = None
@pytest.fixture
def fake_aiohttp(monkeypatch):
"""Install a stand-in ``aiohttp`` module for one test.
aiohttp ships only with Home Assistant, so this mock-only harness
does not have it; the API client imports it lazily inside
``stream_events`` (for ``ClientTimeout``). Tests driving the real
stream path request this fixture; the module is removed again when
the test ends.
"""
module = SimpleNamespace(ClientTimeout=FakeClientTimeout)
monkeypatch.setitem(sys.modules, "aiohttp", module)
return module
@pytest.fixture(autouse=True)
def coordinator_client_from_test_override():
"""Resolve every entry's coordinator client through the test seam.
+27 -1
View File
@@ -17,7 +17,7 @@ import types
import pytest
from conftest import make_config_entry
from conftest import FakeClientTimeout, make_config_entry
from custom_components.nestquest import api_client
from custom_components.nestquest.api_client import (
@@ -33,6 +33,10 @@ from custom_components.nestquest.const import (
DEFAULT_PANEL_TOKEN,
)
# ``stream_events`` imports aiohttp lazily; the harness has none, so
# every test here runs with the stand-in module installed.
pytestmark = pytest.mark.usefixtures("fake_aiohttp")
BASE_URL = "http://api.test:8000"
TOKEN = "test-panel-token"
@@ -124,6 +128,7 @@ class StubTransport:
"url": url,
"headers": kwargs.get("headers"),
"json": kwargs.get("json"),
"timeout": kwargs.get("timeout"),
}
)
if not self._outcomes:
@@ -557,3 +562,24 @@ async def test_stream_events_invalid_json_frame_raises_typed() -> None:
assert excinfo.value.status == 200
assert not excinfo.value.is_transport_error
assert isinstance(excinfo.value.__cause__, ValueError)
async def test_stream_events_disables_the_session_total_timeout() -> None:
"""The stream request overrides the session's default total timeout
(HA's shared session: 300 s, which would cut a healthy stream) with
``total=None`` while keeping a finite connect timeout; the plain
request calls pass no per-request timeout."""
transport = StubTransport(
StubStreamResponse(200, []), StubResponse(200, json.dumps(SNAPSHOT_PAYLOAD))
)
client = make_client(transport, timeout_seconds=7.0)
frames = [frame async for frame in client.stream_events()]
await client.get_snapshot()
assert frames == []
stream_timeout = transport.calls[0]["timeout"]
assert isinstance(stream_timeout, FakeClientTimeout)
assert stream_timeout.total is None
assert stream_timeout.sock_connect == 7.0
assert transport.calls[1]["timeout"] is None
+4
View File
@@ -44,6 +44,10 @@ from custom_components.nestquest.api_client import (
)
from custom_components.nestquest.sse import NestQuestEventStream
# ``stream_events`` imports aiohttp lazily; the harness has none, so
# every test here runs with the stand-in module installed.
pytestmark = pytest.mark.usefixtures("fake_aiohttp")
BASE_URL = "http://api.test:8000"
TOKEN = "test-panel-token"