Skip to content

Add subscription-recovery acceptance tests; bump pytest-asyncio#4

Merged
PostLogical merged 1 commit into
mainfrom
subscription-recovery-spec-tests
May 21, 2026
Merged

Add subscription-recovery acceptance tests; bump pytest-asyncio#4
PostLogical merged 1 commit into
mainfrom
subscription-recovery-spec-tests

Conversation

@PostLogical

Copy link
Copy Markdown
Owner

Summary

Encodes the six fault-injection scenarios from the ops-side recovery spec (2026-05-21 Tawaret incident) as behavioral tests against the library's connection-event surface. The priority case is the false recovery: Tier-1 re-subscribe fires SUBSCRIPTION_RECOVERED (reports success) yet the next poll still diverges and escalates to a Tier-2 forced reconnect — locking in that escalation acts on the next poll's evidence, never Tier-1's self-report.

No runtime/API change; no release (tests, dev deps, and an internal docstring don't ship in the published wheel).

Two spec/library mismatches, handled explicitly

  • 60s reconnect cooldown (spec cases 5c, 6) doesn't exist — it was deleted with the 0.11.0 gap watchdog. Re-expressed as the structural two-poll escalation gate: every forced reconnect is preceded by fresh poll evidence, and no two occur without an intervening mismatch.
  • forced_reconnect_counts / last_subscription_mismatch are integration-side (HA coordinator), not this library. Mapped to event-stream assertions (e.g. forced_reconnect_counts["subscription_mismatch"] == 1 → exactly one FORCED_RECONNECT event with detail.trigger == "subscription_mismatch").

Tests added (tests/test_subscription_recovery_spec.py, 19 cases)

Case Coverage
1 — Tier-1 happy path parametrized over all four notify-backed fields; zero forced reconnects
2 — false recovery (priority) real reconnect path; asserts exact event order MISMATCH→RECOVERED→MISMATCH→FORCED_RECONNECT→CONNECTED, clean poll after
3 — poll failure FORCED_RECONNECT with trigger="poll_failure"
4 — coast immunity 250 stable polls × 4 states, zero events "regardless of duration"
5 — fuzz/soak 5 seeds, silent-drop fault injection (verified non-vacuous: 14–30 forced reconnects/seed), invariants hold
6 — forced reconnect fails failing Tier-2 swallowed, recovery resumes next poll cycle

Also

  • Fix stale trigger value in _execute_forced_reconnect docstring (notify_stallsubscription_mismatch).
  • Bump pytest-asyncio to >=1.0 (1.3.0), dropping the deprecated asyncio.get_event_loop_policy / iscoroutinefunction calls that produced ~18k DeprecationWarnings under Python 3.14. No effect on the CI 3.11–3.13 matrix.

Verification

  • pytest tests/ --cov=ooler_ble_client --cov-fail-under=100399 passed, 100% coverage (0 warnings, was 18,249)
  • mypy --strict ooler_ble_client/ tests/no issues in 13 files

Encode the six fault-injection scenarios from the ops-side recovery spec
(2026-05-21 Tawaret incident) as behavioral tests against the library's
connection-event surface, including the priority false-recovery case
where Tier-1 reports SUBSCRIPTION_RECOVERED yet the next poll still
escalates to a Tier-2 forced reconnect. Two spec/library mismatches are
handled explicitly: the 60s reconnect cooldown (deleted with the 0.11.0
gap watchdog) is re-expressed as the structural two-poll escalation gate,
and integration-side counters (forced_reconnect_counts,
last_subscription_mismatch) are mapped to event-stream assertions since
they live in the HA coordinator, not this library.

Also fix a stale trigger value in the _execute_forced_reconnect docstring
(notify_stall -> subscription_mismatch) and bump pytest-asyncio to >=1.0,
which drops the deprecated asyncio.get_event_loop_policy /
iscoroutinefunction calls that produced ~18k DeprecationWarnings under
Python 3.14 (no effect on CI's 3.11-3.13 matrix).

No release: tests, dev deps, and an internal docstring do not affect the
published package.
@PostLogical
PostLogical merged commit 5f2d7f6 into main May 21, 2026
3 checks passed
@PostLogical
PostLogical deleted the subscription-recovery-spec-tests branch May 21, 2026 22:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant