fix(config_flow): D3 — await the discovery-dedup coroutine (t37)
`ConfigFlow._async_handle_discovery_without_unique_id` is an `async def` in core (verified: `inspect.iscoroutinefunction` is True) and core awaits it. t32 called it without `await`, so the coroutine body never ran: no `already_configured` abort when the handler already had entries, no `DEFAULT_DISCOVERY_UNIQUE_ID` claim, no `already_in_progress` abort — HA's discovery dedup was dead, Python warned "coroutine ... was never awaited", and the host-equality loop that used to sit here was the only accidental dedup. The call is awaited and the now-unreachable host loop is gone (the real helper is stricter: any entry for the domain, or any in-flight flow). The harness mirrors the real contract instead of a sync no-op: * `entity_stublib`'s hub stub makes the helper a coroutine (a sync stub would turn the production `await` into a TypeError); * `test_standalone_setup`'s stub models the real semantics — a coroutine raising `DiscoveryDedupAbortError` (core raises AbortFlow), driven by the shared holder's entry list and in-progress list — and its tests now assert all three outcomes: awaited-and-proceeds (counter + claimed discovery unique id), `already_configured` when entries exist, `already_in_progress` when another flow runs. A fourth test collects the un-awaited-coroutine warning, and the prefill test in the UX suite asserts the awaited counter. Red proof: with the pre-fix config_flow.py the repo-owned sweep reports `config_flow.py:425: missing-await: self._async_handle_discovery_without_unique_id()`. Verified: 289 passed, 2 skipped (D3 stage); ruff clean.
This commit is contained in:
1 parent
bd72ae3170
commit
60fb4f7557
4 files changed
+115
-34
No files matched your search
@@ -417,18 +417,17 @@ class NvidiaShieldConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
return self.async_abort(reason="already_configured")
|
||||
self._abort_if_unique_id_configured()
|
||||
else:
|
||||
# t32 F2 (review rider): MAC-less discovery cannot carry a
|
||||
# unique_id — HA's helper records the uniqueness-less discovery
|
||||
# (the same discovery context can't stack duplicates) and the
|
||||
# host guard keeps a second discovery of an already-configured
|
||||
# host from stacking another prefill.
|
||||
self._async_handle_discovery_without_unique_id()
|
||||
for entry in self._async_current_entries():
|
||||
existing_host = entry.options.get(
|
||||
CONF_PROTOCOL_HOST
|
||||
) or entry.options.get(CONF_ADB_HOST)
|
||||
if existing_host and existing_host == host:
|
||||
return self.async_abort(reason="already_configured")
|
||||
# t32 F2 / t37 D3: MAC-less discovery cannot carry a unique_id, so
|
||||
# HA's own helper owns the dedup — and it MUST be awaited. It is a
|
||||
# coroutine that aborts `already_configured` when the handler
|
||||
# already has entries, claims DEFAULT_DISCOVERY_UNIQUE_ID, and
|
||||
# aborts `already_in_progress` when another flow for this handler
|
||||
# is running. t32 shipped the call without the await, so none of
|
||||
# that ran ("coroutine was never awaited") and the host-equality
|
||||
# guard that used to sit here was the accidental dedup; the real
|
||||
# helper is stricter (any entry for the domain, any in-flight
|
||||
# flow), so nothing is left to do here.
|
||||
await self._async_handle_discovery_without_unique_id()
|
||||
|
||||
# First-time setup: pre-filled user step
|
||||
return await self.async_step_user()
|
||||
|
||||
Reference in new issue
Block a user