complete_quest proxies to the API so the panel tap is one write

WHY: Feature 18 makes the integration a client of the NestQuest API
service — every database write must go through the API.  The
complete_quest service still wrote the local database and fired the
completed event itself, which would double-fire once the SSE
subscription re-fires the API's transition (and stops being true the
moment the local database is dropped).  The service now proxies to the
entry's ONE shared API client (complete_instance: the panel complete
route) and keeps only the old immediate-update behaviour: a successful
call refreshes the coordinator so the sensors reflect the completion
at once; the bus event comes solely from the SSE stream.  Typed API
failures (and an unconfigured client, and a non-panel actor) surface
as HomeAssistantError with token-free messages instead of being
swallowed; the payload contract (instance_id, actor=panel,
actor_child_id) is unchanged for the panel cards.

Tests: new tests/test_complete_quest_proxy.py asserts the call reaches
the shared client with the right arguments, that no local write or
local event happens on the API path, that a non-2xx/transport failure
raises a service error chained to the typed error (never containing
the token), and that the unconfigured stub fails clearly.  Existing
tests that drove complete_quest through the local database move to the
API path via the harness stand-in client (which performs the same core
completion and publishes the same SSE frames the API route does) and
assert their bus events after the frames are delivered through the
real SSE subscription; the shim-level tests drive the events shim
directly, the way its remaining callers invoke it.

Task 47c7c90e (complete_quest proxies to the API, Feature 18).
This commit is contained in:
2026-09-23 07:44:46 -04:00
parent 84d179336b
commit ffda0a2ed7
5 changed files with 585 additions and 47 deletions
+10 -1
View File
@@ -14,7 +14,7 @@ from __future__ import annotations
import datetime
import re
from conftest import wire_entry_to_registry
from conftest import refire_api_transitions, wire_entry_to_registry
from custom_components.nestquest import async_setup_entry
from custom_components.nestquest.children import (
@@ -154,6 +154,11 @@ async def test_entity_and_event_matrix(hass, make_entry) -> None:
"actor_child_id": ada.id,
},
)
# The transition events arrive over the API's SSE stream (the
# subscription re-fires them), never from the service handler.
await refire_api_transitions(
hass, entry, entry.runtime_data.coordinator.api_client
)
assert len(hass.bus.fired(EVENT_QUEST_COMPLETED)) == 2
for payload in hass.bus.fired(EVENT_QUEST_COMPLETED):
assert _TIMESTAMP.match(payload["occurred_at"])
@@ -234,6 +239,10 @@ async def test_payload_schema_matches_the_documented_contract(
"actor_child_id": ada.id,
},
)
# The completed event arrives over the API's SSE stream.
await refire_api_transitions(
hass, entry, entry.runtime_data.coordinator.api_client
)
payload = hass.bus.fired(EVENT_QUEST_COMPLETED)[0]
for key, check in (
("child_id", lambda v: isinstance(v, int)),