Skip to content

Commit 690622a

Browse files
committed
test(e2e): add per-lane skip-count ceiling + tighten dispatch smoke docstrings
Addresses the gap surfaced by pr-test-analyzer review: none of the three existing dispatch smoke tests catch the "tests transition pass → skip silently" failure mode. The conftest itself documents a real prior incident of this class at tests/src/e2e/conftest.py:158-166 (PR #1375 audit, 14 supervisor_mock tests silently skipping on every testcontainer run because an external_only marker was scoped wrong). Adds: - test_session_skipped_count_below_ceiling: counts items with skip markers in request.session.items and asserts the count stays below a per-lane ceiling. Baseline 2026-05-22: container=46, haos=14, haos_inaddon=22. Ceilings set 5-9 above current to absorb normal marker-gated additions without flapping, while still catching a ~10+ test mass-skip incident. Also tightens three docstrings flagged by the comment-analyzer review: - Test 1 docstring now notes test-side env check is an approximation of conftest's is_haos_backend_selected (which also checks path existence), and explains why the test deliberately doesn't share the helper. - Test 2 docstring is precise about the failure path on testcontainer (raises ToolError → safe_call_tool decodes to success=False) and flags the dict-conversion as load-bearing so a future maintainer doesn't "simplify" to assert_mcp_failure. - Test 3 docstring acknowledges the 3-test variance between container (912) and HAOS (915) lanes rather than calling collection "mode-independent."
1 parent a6ede04 commit 690622a

1 file changed

Lines changed: 87 additions & 11 deletions

File tree

tests/src/e2e/basic/test_backend_dispatch_smoke.py

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828
collection-time regressions where a test file fails to import and
2929
pytest silently drops tens of tests.
3030
31+
4. ``test_session_skipped_count_below_ceiling`` — per-lane skip-count
32+
ceiling. Catches the inverse of #3: collection size unchanged but
33+
tests transition pass→skip silently because a marker was applied
34+
too broadly. The conftest documents a prior incident of this kind
35+
(PR #1375 audit, 14 ``supervisor_mock`` tests silently skipping on
36+
every testcontainer run — see ``tests/src/e2e/conftest.py:158-166``).
37+
3138
This file is placed under ``basic/`` (NOT ``haos_only/``) on purpose: the
3239
auto-applied ``haos_only`` marker would skip these whenever
3340
``is_haos_backend_selected()`` returns False, which is exactly the
@@ -42,21 +49,39 @@
4249

4350
from ..utilities.assertions import safe_call_tool
4451

45-
# Floor for total collected tests across all lanes. As of 2026-05-22 each
46-
# lane collects ~913 tests (just differing skip mix per mode). Set well
47-
# below current value to allow normal test-add/remove churn while still
48-
# catching the case where ~50+ tests vanish from collection.
52+
# Floor for total collected tests across all lanes. As of 2026-05-22
53+
# container lanes collect 912 and HAOS lanes collect 915 (small per-mode
54+
# variance from parametrize/fixture-driven cases). Floor sits well below
55+
# all three to allow normal test-add/remove churn while still catching
56+
# the case where ~50+ tests vanish from collection.
4957
_COLLECTION_FLOOR = 850
5058

59+
# Per-lane ceilings for the count of skip-marked tests. Set 5-9 above
60+
# current per-lane skip counts (as of 2026-05-22: container=46,
61+
# haos=14, haos_inaddon=22). A buffer of 5-9 absorbs PRs that
62+
# legitimately add a few new marker-gated tests, but catches a
63+
# mass-skip incident like PR #1375 (14 tests started skipping silently
64+
# because a marker was applied too broadly).
65+
_SKIP_CEILING_PER_LANE = {
66+
"container": 55,
67+
"haos": 20,
68+
"haos_inaddon": 30,
69+
}
70+
5171

5272
def test_backend_dispatch_matches_workflow_env(
5373
ha_container_with_fresh_config: dict[str, Any],
5474
) -> None:
5575
"""Conftest dispatch must pick the backend the workflow env implies.
5676
57-
Runs unconditionally on every lane — branches off env vars to mirror
58-
conftest's own dispatch logic. Mismatch means the dispatch silently
59-
picked a different backend than CI asked for.
77+
Runs unconditionally on every lane — branches off env vars to
78+
approximate conftest's dispatch logic. (Conftest's
79+
``is_haos_backend_selected`` additionally requires the qcow2 file
80+
to exist on disk; this test only checks env-var truthiness. The
81+
test deliberately re-derives the expected backend independently
82+
rather than calling the same helper, so a helper-side regression
83+
can't make the test silently agree with the bug.) Mismatch means
84+
the dispatch silently picked a different backend than CI asked for.
6085
"""
6186
image_path = os.environ.get("HAOS_TEST_IMAGE_PATH")
6287
mode = os.environ.get("HAOS_TEST_MODE", "")
@@ -108,8 +133,12 @@ async def test_supervisor_addon_tool_behavior_matches_backend(
108133
109134
- HAOS external + inaddon: ``ha_get_addon`` returns a populated
110135
addons list (the bake installs several addons).
111-
- testcontainer: ``ha_get_addon`` returns ``success=False`` because
112-
the Supervisor proxy endpoint is unreachable.
136+
- testcontainer: ``ha_get_addon`` raises ToolError
137+
(RESOURCE_NOT_FOUND from the ``supervisor/api`` WebSocket proxy
138+
because no Supervisor is running); ``safe_call_tool`` catches
139+
and decodes the structured error to ``{"success": False, ...}``.
140+
The dict conversion is load-bearing — a future maintainer should
141+
NOT switch to ``assert_mcp_failure`` or similar.
113142
114143
The asymmetry of this check makes it impossible for one backend to
115144
impersonate the other while keeping this test green.
@@ -145,12 +174,59 @@ def test_session_collected_test_count_above_floor(request: Any) -> None:
145174
146175
Catches collection-time regressions: a test file fails to import,
147176
pytest collects tens of fewer tests, the suite stays green with
148-
reduced coverage. Collection count is mode-independent (all lanes
149-
collect the same items, mode only changes pass/skip mix).
177+
reduced coverage. Collection count varies by a handful across
178+
modes (parametrize/fixture-driven — currently 912 container vs
179+
915 HAOS lanes); the floor sits well below all three lanes' actuals.
150180
"""
151181
total = len(request.session.items)
152182
assert total >= _COLLECTION_FLOOR, (
153183
f"Only {total} tests collected, expected >= {_COLLECTION_FLOOR}. "
154184
f"A test file likely failed to import, dropping coverage. Check "
155185
f"for collection errors in the pytest output."
156186
)
187+
188+
189+
def test_session_skipped_count_below_ceiling(
190+
request: Any,
191+
ha_container_with_fresh_config: dict[str, Any],
192+
) -> None:
193+
"""Per-lane skip-count must stay below ``_SKIP_CEILING_PER_LANE[backend]``.
194+
195+
Catches the inverse of the collection-floor check: the suite still
196+
collects the expected total, but tests transition pass→skip silently
197+
because a marker was applied too broadly in conftest's
198+
``pytest_collection_modifyitems`` hook.
199+
200+
The conftest itself documents a real prior incident of this kind
201+
(``tests/src/e2e/conftest.py:158-166`` — PR #1375 audit, 14
202+
``supervisor_mock`` tests silently skipping on every testcontainer
203+
run because an ``external_only`` skip was scoped wrong). A
204+
skip-count ceiling per lane catches that whole class of bug.
205+
206+
Ceilings sit 5-9 above current per-lane skip counts; updates are
207+
only required when a PR legitimately introduces enough new
208+
marker-gated tests to cross the threshold (uncommon).
209+
"""
210+
backend = ha_container_with_fresh_config["backend"]
211+
ceiling = _SKIP_CEILING_PER_LANE.get(backend)
212+
assert ceiling is not None, (
213+
f"Unknown backend {backend!r} — add to _SKIP_CEILING_PER_LANE "
214+
f"at the top of this file"
215+
)
216+
# Items in request.session.items already have skip markers applied
217+
# by pytest_collection_modifyitems (which ran before any test).
218+
# Under pytest-xdist with --dist loadscope, each worker collects
219+
# the full session, so this count is consistent per worker.
220+
skipped = sum(
221+
1
222+
for item in request.session.items
223+
if any(m.name == "skip" for m in item.iter_markers())
224+
)
225+
assert skipped <= ceiling, (
226+
f"{skipped} tests have skip markers on the {backend} lane, "
227+
f"which exceeds the ceiling of {ceiling}. A marker may be "
228+
f"applied too broadly in pytest_collection_modifyitems — "
229+
f"check tests/src/e2e/conftest.py:115-168 for recent changes. "
230+
f"If the increase is intentional (legitimate new marker-gated "
231+
f"tests), bump _SKIP_CEILING_PER_LANE[{backend!r}] in this file."
232+
)

0 commit comments

Comments
 (0)