test: invoke the scheduled sweep instead of faking a 24 h jump

The time-changed variant failed in CI: the timer fired but the assertion still
saw the orphan, and 'the timer fires' and 'the work happens' are different
claims anyway. HouseplanData now publishes the sweep, so the test awaits it
directly and asserts the outcome.
This commit is contained in:
Matysh
2026-07-28 19:35:09 +03:00
parent c9a60a110d
commit 254354bf56
3 changed files with 16 additions and 6 deletions
+1
View File
@@ -142,6 +142,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: HouseplanConfigEntry) ->
except Exception: # noqa: BLE001 — housekeeping must never fail a setup except Exception: # noqa: BLE001 — housekeeping must never fail a setup
_LOGGER.exception("House Plan: sweeping unreferenced files failed") _LOGGER.exception("House Plan: sweeping unreferenced files failed")
data.sweep = _sweep
await _sweep() await _sweep()
entry.async_on_unload( entry.async_on_unload(
async_track_time_interval(hass, _sweep, timedelta(hours=24)) async_track_time_interval(hass, _sweep, timedelta(hours=24))
+6
View File
@@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any from typing import Any
@@ -42,6 +43,11 @@ class HouseplanData:
# One lock for every load→modify→save cycle of both stores: prevents # One lock for every load→modify→save cycle of both stores: prevents
# lost updates from concurrent WS calls and makes the rev check atomic. # lost updates from concurrent WS calls and makes the rev check atomic.
write_lock: asyncio.Lock = field(default_factory=asyncio.Lock) write_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
# Collect files nothing references any more. Set during setup, which also
# runs it once and schedules it daily. Exposed so it can be invoked
# directly — a test that fakes a 24 h jump proves the timer fires, not that
# the work happens, and those are different claims.
sweep: Callable[[], Awaitable[None]] | None = None
HouseplanConfigEntry = ConfigEntry[HouseplanData] HouseplanConfigEntry = ConfigEntry[HouseplanData]
+9 -6
View File
@@ -938,14 +938,15 @@ async def test_startup_sweep_collects_what_no_commit_will(
), "the emptied staging folder goes with its last file" ), "the emptied staging folder goes with its last file"
async def test_daily_sweep_callback_collects_too( async def test_periodic_sweep_collects_too(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None: ) -> None:
"""The interval path, exercised on its own by firing the scheduled callback.""" """The scheduled pass, invoked directly rather than by faking a 24 h jump.
import datetime as dt
from homeassistant.util import dt as dt_util Firing a time change proves the timer fires; awaiting the callback proves it
from pytest_homeassistant_custom_component.common import async_fire_time_changed does the work. This asserts the second, which is the part that regressed.
"""
from custom_components.houseplan.store import get_data
await _setup(hass) await _setup(hass)
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
@@ -954,7 +955,9 @@ async def test_daily_sweep_callback_collects_too(
await _seed_aged(hass, list(p.values())) await _seed_aged(hass, list(p.values()))
async_fire_time_changed(hass, dt_util.utcnow() + dt.timedelta(hours=25)) data = get_data(hass)
assert data is not None and data.sweep is not None, "setup must publish the sweep"
await data.sweep()
await hass.async_block_till_done() await hass.async_block_till_done()
await _assert_swept(hass, p) await _assert_swept(hass, p)