Skip to content

Commit b8709ab

Browse files
committed
fix(test): sanitize entity_id in _backups_for + use list_groups for group poll
Two follow-ups after the previous merge run cleared 2 of 5 failures but exposed two distinct test-side bugs in what was left: 1. ``_backups_for`` filter was still comparing original entity_id against the sanitized form returned by ``list_snapshots``. ``list_snapshots`` itself now sanitizes its filter argument (so the backend correctly returns matching entries), but the ``_backups_for`` python-side filter in the test re-checks equality against the original composite ID — which never matches the sanitized form on ``area:foo`` / ``automation:cat_id`` style IDs. Apply ``_safe_entity_id`` symmetrically so both sides of the comparison go through the same function. 2. Group's ``ha_get_state`` poll timed out at 15 s because the ``/api/states/group.<id>`` propagation lags by several seconds on fresh testcontainers. The existing ``tests/.../groups/ test_lifecycle.py`` proves ``ha_config_list_groups`` surfaces a newly-created group with no wait at all. Switch the group test's readiness poll to ``ha_config_list_groups`` (timeout 20 s for headroom) — by the time list_groups returns our group, the service-call has finished and the decorator's pre-edit ``/api/states/group.<id>`` GET should succeed.
1 parent 356b5e4 commit b8709ab

1 file changed

Lines changed: 25 additions & 11 deletions

File tree

tests/src/e2e/workflows/auto_backup/test_capture_and_restore.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,19 @@ def _enable_auto_backup(monkeypatch: pytest.MonkeyPatch) -> None:
4747
def _backups_for(
4848
entries: list[dict[str, Any]], *, domain: str, entity_id: str
4949
) -> list[dict[str, Any]]:
50-
return [e for e in entries if e["domain"] == domain and e["entity_id"] == entity_id]
50+
"""Filter list-snapshots entries by domain + entity_id.
51+
52+
Snapshot filenames are sanitized (``_safe_entity_id`` replaces every
53+
char outside ``[A-Za-z0-9._-]`` with ``_``), and ``list_snapshots``
54+
returns the parsed-from-filename entity_id — so a caller filtering
55+
with a composite ID like ``area:foo`` would otherwise never match
56+
the stored ``area_foo``. Sanitize both sides through the same
57+
function for a symmetric comparison.
58+
"""
59+
from ha_mcp.backup_manager import _safe_entity_id
60+
61+
safe_id = _safe_entity_id(entity_id)
62+
return [e for e in entries if e["domain"] == domain and e["entity_id"] == safe_id]
5163

5264

5365
# Fixed delay between create and edit to let HA's WS-backed registries
@@ -1027,19 +1039,21 @@ async def test_group_full_loop(
10271039
pytest.skip(f"group create unsupported: {create}")
10281040
# Group entity is created via the ``group.set`` service call —
10291041
# state machine registration is async and a fixed sleep is racy.
1030-
# Poll ``ha_get_state`` until ``group.<object_id>`` is queryable
1031-
# so the decorator's pre-edit ``/api/states`` GET finds it.
1042+
# Poll ``ha_config_list_groups`` until our group appears in the
1043+
# configured-groups list, which surfaces sooner than the
1044+
# ``/api/states/group.<id>`` propagation (the latter can lag by
1045+
# several seconds on fresh testcontainers; the previous
1046+
# ``ha_get_state`` poll timed out at 15 s).
10321047
await wait_for_tool_result(
10331048
mcp_client,
1034-
tool_name="ha_get_state",
1035-
arguments={"entity_id": f"group.{object_id}"},
1036-
predicate=lambda d: (
1037-
d.get("success") is True
1038-
or d.get("state") is not None
1039-
or d.get("entity_id") == f"group.{object_id}"
1049+
tool_name="ha_config_list_groups",
1050+
arguments={},
1051+
predicate=lambda d: any(
1052+
g.get("object_id") == object_id
1053+
for g in (d.get("groups", []) or d.get("data", {}).get("groups", []))
10401054
),
1041-
description=f"group.{object_id} state visible",
1042-
timeout=15,
1055+
description=f"group {object_id} in list_groups",
1056+
timeout=20,
10431057
)
10441058

10451059
edit = await safe_call_tool(

0 commit comments

Comments
 (0)