"""Integration: the newest Traefik row per router, read by walking the (router_name, scraped_at) index rather than grouping every row (#5254). Requires STEWARD_DATABASE_URL.""" from __future__ import annotations import asyncio import os import uuid 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_each_router_reads_as_its_newest_row(app): from plugins.traefik.models import TraefikMetric from plugins.traefik.routes import latest_per_router now = datetime.now(timezone.utc).replace(microsecond=0) tag = uuid.uuid4().hex[:8] a, b = f"a-{tag}@docker", f"b-{tag}@docker" def row(name, ago, rate): return TraefikMetric(router_name=name, scraped_at=now - timedelta(minutes=ago), request_rate=rate, error_rate_4xx_pct=0.0, error_rate_5xx_pct=0.0, latency_p50_ms=1.0, latency_p95_ms=2.0, latency_p99_ms=3.0, response_bytes_rate=0.0) async def go(): async with app.db_sessionmaker() as s: async with s.begin(): s.add_all([row(a, 3, 1.0), row(a, 1, 2.0), row(a, 2, 3.0), row(b, 5, 4.0)]) async with s.begin(): return {m.router_name: m for m in await latest_per_router(s)} got = asyncio.run(go()) assert got[a].request_rate == 2.0 and got[a].scraped_at == now - timedelta(minutes=1) assert got[b].request_rate == 4.0 def test_the_request_chart_sums_routers_and_weights_the_5xx_share(app): """#5256: two routers in one scrape are 4 req/s in total, not an average of 2; a 5xx share of 50% on the 3 req/s router is 37.5% of all traffic.""" from plugins.traefik.models import TraefikMetric from plugins.traefik.routes import request_history # Far ahead of every other test's rows, so only these fall in the window. at = datetime(2099, 1, 1, 12, 0, tzinfo=timezone.utc) + timedelta(minutes=uuid.uuid4().int % 10_000) def row(name, rate, e5): return TraefikMetric(router_name=name, scraped_at=at, request_rate=rate, error_rate_4xx_pct=0.0, error_rate_5xx_pct=e5, latency_p50_ms=1.0, latency_p95_ms=2.0, latency_p99_ms=3.0, response_bytes_rate=0.0) async def go(): async with app.db_sessionmaker() as s: async with s.begin(): s.add_all([row("quiet@docker", 1.0, 0.0), row("busy@docker", 3.0, 50.0)]) async with s.begin(): return await request_history(s, at, 60) got = asyncio.run(go()) assert got == [{"at": at, "req_rate": 4.0, "err_pct": 37.5}]