Files
FabledSteward/tests/integration/test_unifi_history.py
T
bvandeusenandClaude Opus 5.5 ea31deabf9
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m24s
CI / unit (push) Successful in 1m35s
CI / publish (push) Successful in 1m29s
fix(unifi): the Overview's history buckets on Postgres; devices name their state (#5207)
#5207 "UniFi Overview tab: func.strftime is SQLite-only": the WAN and
client sparklines bucketed with strftime('%s'), which Postgres lacks, so
/plugins/unifi/rows failed. Traefik's date_bin bucket moves to
core/time_range.time_bucket and both plugins use it. Devices list offline
and failing first, and a state other than online is named (Upgrading,
Adopting, Heartbeat missed...) instead of drawn as Down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:28:19 -04:00

53 lines
2.2 KiB
Python

"""Integration: the UniFi overview's sparkline history buckets on Postgres
(#5207: it used SQLite's strftime, so the overview rows failed). Requires
STEWARD_DATABASE_URL."""
from __future__ import annotations
import asyncio
import os
from datetime import datetime, timedelta, timezone
import pytest
pytestmark = pytest.mark.integration
@pytest.fixture
def app():
if not os.environ.get("STEWARD_DATABASE_URL"):
pytest.skip("needs Postgres")
from steward.app import create_app
return create_app(testing=False)
def test_wan_and_client_history_average_per_window(app):
from sqlalchemy import delete
from plugins.unifi.models import UnifiClientSnapshot, UnifiWanStat
from plugins.unifi.routes import history
# Two scrapes in one 10-minute window, one in the next.
start = datetime(2031, 1, 1, 12, 0, tzinfo=timezone.utc)
at = [start + timedelta(minutes=1), start + timedelta(minutes=4), start + timedelta(minutes=12)]
async def go():
async with app.db_sessionmaker() as s:
async with s.begin():
await s.execute(delete(UnifiWanStat).where(UnifiWanStat.scraped_at >= start))
await s.execute(delete(UnifiClientSnapshot).where(UnifiClientSnapshot.scraped_at >= start))
for when, ms, n in zip(at, (10.0, 30.0, 50.0), (4, 6, 9)):
s.add(UnifiWanStat(scraped_at=when, is_up=True, latency_ms=ms,
rx_bytes_rate=1.0, tx_bytes_rate=2.0))
s.add(UnifiClientSnapshot(scraped_at=when, total_clients=n))
try:
async with s.begin():
return await history(s, start, 600)
finally:
async with s.begin():
await s.execute(delete(UnifiWanStat).where(UnifiWanStat.scraped_at >= start))
await s.execute(delete(UnifiClientSnapshot).where(UnifiClientSnapshot.scraped_at >= start))
wan, clients = asyncio.run(go())
assert [(r.latency_ms, r.scraped_at, r.bucket) for r in wan] == [
(20.0, at[0], start), (50.0, at[2], start + timedelta(minutes=10))]
assert [float(r.total_clients) for r in clients] == [5.0, 9.0]