Files
bvandeusenandClaude Opus 5.5 73cfbda1da
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m10s
CI / unit (push) Successful in 1m26s
CI / publish (push) Successful in 1m5s
fix(alerts): a rule's page doesn't wait for its metric preview (#5485); Send test up top (#5486)
#5485 "A rule's page waits up to 25 s for its metric preview: a cold 24 h
series read from plugin_metrics". Opening "Agent offline" took 25.6 s; a
cold day of one series measured 18.3 s over MCP, a warm one 63 ms. The
pickers still come with the page from plugin_metric_latest; the preview is
its own request (hx-trigger=load), showing "Reading the last day…" until it
lands. Picker swaps no longer read it either.

#5486 "Send test where it can be found": the button moves from inside "What
happens" to the page header beside History, its result under the verdict.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:44:19 -04:00

71 lines
3.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Integration: the rule form's host and part pickers and the metric preview
(#5475), through their routes against Postgres. A host's parts come grouped
under it, and a picked metric shows what it reads now and over the last day."""
from __future__ import annotations
import asyncio
import os
import time
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_the_pickers_and_the_preview_read_what_the_host_reports(app):
from steward.core.alerts import record_metrics
from steward.models.metrics import PluginMetric
from steward.models.users import User, UserRole
async def _go():
tag = uuid.uuid4().hex[:8]
host = f"rf-{tag}"
now = datetime.now(timezone.utc)
async with app.db_sessionmaker() as s:
async with s.begin():
user = User(username=f"rf-{tag}", email=f"rf-{tag}@test", password_hash="x",
role=UserRole.operator, is_active=True)
s.add(user)
# Disk use climbing over the last few hours, then cpu and a mount.
await record_metrics(s, [
PluginMetric(source_module="host_agent", resource_name=f"{host}:/data",
metric_name="disk_used_pct", value=v, recorded_at=now - timedelta(hours=h))
for h, v in ((5, 61.0), (3, 70.0), (1, 82.0))])
await record_metrics(s, [
PluginMetric(source_module="host_agent", resource_name=host,
metric_name="cpu_pct", value=12.0, recorded_at=now)])
uid = user.id
client = app.test_client()
async with client.session_transaction() as sess:
sess.update(user_id=uid, user_role="operator", username=f"rf-{tag}",
_csrf="test-token", login_at=time.time())
resp = await client.get("/alerts/api/rule_target", query_string={
"source_module": "host_agent", "pick_host": host, "metric_name": "cpu_pct"})
page = " ".join((await resp.get_data(as_text=True)).split())
assert resp.status_code == 200
assert f'<option value="{host}" selected>The whole host</option>' in page
assert f'<optgroup label="Mounts"> <option value="{host}:/data" >/data</option>' in page
# #5485: the pickers come without the preview, which loads in its own request.
assert 'hx-get="/alerts/api/metric_preview" hx-trigger="load"' in page
assert "Reading the last day" in page and "Now <strong>" not in page
resp = await client.get("/alerts/api/metric_preview", query_string={
"source_module": "host_agent", "pick_host": host, "resource_name": f"{host}:/data",
"metric_name": "disk_used_pct"})
page = " ".join((await resp.get_data(as_text=True)).split())
assert "Now <strong>82%</strong>" in page
assert "last 24 h</span> 61% – 82%" in page and "<polyline" in page
asyncio.run(_go())