test(alerts): seed metrics the way ingest does, through record_metrics (#5473)
CI / lint (push) Successful in 3s
CI / integration (push) Successful in 1m10s
CI / unit (push) Successful in 1m37s
CI / publish (push) Successful in 1m11s

#5473 "Opening an alert rule takes up to 15 s". With the rule pickers now
reading plugin_metric_latest, nine integration tests failed on rule_fields:
"host_agent has no resource 'box-…'". They seeded a resource by adding a raw
PluginMetric row, which no production path does: host-agent ingest and
record_metric both go through record_metrics, which keeps the latest-value
table. The seeds now go through record_metrics too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 09:28:53 -04:00
co-authored by Claude Opus 5.5
parent ee1f7b782d
commit d5601575d8
5 changed files with 20 additions and 16 deletions
+3 -2
View File
@@ -25,6 +25,7 @@ def app():
async def _rule(app, tag, **extra): async def _rule(app, tag, **extra):
from steward.alerts import service as alert_svc from steward.alerts import service as alert_svc
from steward.core.alerts import record_metrics
from steward.models.metrics import PluginMetric from steward.models.metrics import PluginMetric
from steward.models.users import User, UserRole from steward.models.users import User, UserRole
res = f"box-{tag}" res = f"box-{tag}"
@@ -33,8 +34,8 @@ async def _rule(app, tag, **extra):
user = User(username=f"dp-{tag}", email=f"dp-{tag}@test", password_hash="x", user = User(username=f"dp-{tag}", email=f"dp-{tag}@test", password_hash="x",
role=UserRole.admin) role=UserRole.admin)
s.add(user) s.add(user)
s.add(PluginMetric(source_module="host_agent", resource_name=res, await record_metrics(s, [PluginMetric(source_module="host_agent", resource_name=res,
metric_name="cpu_pct", value=1.0)) metric_name="cpu_pct", value=1.0)])
await s.flush() await s.flush()
fields = await alert_svc.rule_fields( fields = await alert_svc.rule_fields(
s, name=f"hot {tag}", source_module="host_agent", resource_name=res, s, name=f"hot {tag}", source_module="host_agent", resource_name=res,
+6 -6
View File
@@ -45,9 +45,9 @@ def test_silence_is_marked_once_and_cleared_by_data(app):
user = User(username=f"nd-{tag}", email=f"nd-{tag}@test", password_hash="x", user = User(username=f"nd-{tag}", email=f"nd-{tag}@test", password_hash="x",
role=UserRole.admin) role=UserRole.admin)
s.add(user) s.add(user)
s.add(PluginMetric(source_module="host_agent", resource_name=res, await alerts.record_metrics(s, [PluginMetric(
metric_name="cpu_pct", value=1.0, source_module="host_agent", resource_name=res, metric_name="cpu_pct",
recorded_at=now - timedelta(hours=1))) value=1.0, recorded_at=now - timedelta(hours=1))])
await s.flush() await s.flush()
ids = {} ids = {}
for key, notify in (("loud", True), ("hushed", False)): for key, notify in (("loud", True), ("hushed", False)):
@@ -156,9 +156,9 @@ def test_a_series_quiet_only_while_steward_was_down_is_not_silent(app):
user = User(username=f"bk-{tag}", email=f"bk-{tag}@test", password_hash="x", user = User(username=f"bk-{tag}", email=f"bk-{tag}@test", password_hash="x",
role=UserRole.admin) role=UserRole.admin)
s.add(user) s.add(user)
s.add(PluginMetric(source_module="host_agent", resource_name=res, await alerts.record_metrics(s, [PluginMetric(
metric_name="cpu_pct", value=1.0, source_module="host_agent", resource_name=res, metric_name="cpu_pct",
recorded_at=now - timedelta(minutes=18))) value=1.0, recorded_at=now - timedelta(minutes=18))])
await s.flush() await s.flush()
fields = await alert_svc.rule_fields( fields = await alert_svc.rule_fields(
s, name=f"back {tag}", source_module="host_agent", resource_name=res, s, name=f"back {tag}", source_module="host_agent", resource_name=res,
+4 -4
View File
@@ -24,7 +24,7 @@ def app():
def test_acknowledge_holds_clear_after_and_reset(app): def test_acknowledge_holds_clear_after_and_reset(app):
from sqlalchemy import select from sqlalchemy import select
from steward.alerts import service as alert_svc from steward.alerts import service as alert_svc
from steward.core.alerts import record_metric from steward.core.alerts import record_metric, record_metrics
from steward.models.alerts import AlertEvent, AlertRule, AlertState, AlertStateEnum from steward.models.alerts import AlertEvent, AlertRule, AlertState, AlertStateEnum
from steward.models.metrics import PluginMetric from steward.models.metrics import PluginMetric
from steward.models.users import User, UserRole from steward.models.users import User, UserRole
@@ -37,8 +37,8 @@ def test_acknowledge_holds_clear_after_and_reset(app):
user = User(username=f"al-{tag}", email=f"al-{tag}@test", password_hash="x", user = User(username=f"al-{tag}", email=f"al-{tag}@test", password_hash="x",
role=UserRole.admin) role=UserRole.admin)
s.add(user) s.add(user)
s.add(PluginMetric(source_module="host_agent", resource_name=res, await record_metrics(s, [PluginMetric(source_module="host_agent", resource_name=res,
metric_name="cpu_pct", value=1.0)) metric_name="cpu_pct", value=1.0)])
await s.flush() await s.flush()
fields = await alert_svc.rule_fields( fields = await alert_svc.rule_fields(
s, name=f"hot {tag}", source_module="host_agent", resource_name=res, s, name=f"hot {tag}", source_module="host_agent", resource_name=res,
@@ -154,7 +154,7 @@ def test_record_metrics_marks_each_step(app):
user = User(username=f"mk-{tag}", email=f"mk-{tag}@test", password_hash="x", user = User(username=f"mk-{tag}", email=f"mk-{tag}@test", password_hash="x",
role=UserRole.admin) role=UserRole.admin)
s.add(user) s.add(user)
s.add_all(rows(watched)) await record_metrics(s, rows(watched))
await s.flush() await s.flush()
fields = await alert_svc.rule_fields( fields = await alert_svc.rule_fields(
s, name=f"hot {tag}", source_module="host_agent", resource_name=watched, s, name=f"hot {tag}", source_module="host_agent", resource_name=watched,
+3 -2
View File
@@ -31,6 +31,7 @@ def test_ingest_fires_a_host_rule_from_a_backlog(app):
from steward.alerts import service as alert_svc from steward.alerts import service as alert_svc
from steward.models.alerts import AlertEvent, AlertState, AlertStateEnum from steward.models.alerts import AlertEvent, AlertState, AlertStateEnum
from steward.models.hosts import Host from steward.models.hosts import Host
from steward.core.alerts import record_metrics
from steward.models.metrics import PluginMetric from steward.models.metrics import PluginMetric
from steward.models.users import User, UserRole from steward.models.users import User, UserRole
@@ -50,8 +51,8 @@ def test_ingest_fires_a_host_rule_from_a_backlog(app):
"VALUES (:id, :host, :hash, now(), now(), now())"), "VALUES (:id, :host, :hash, now(), now(), now())"),
{"id": str(uuid.uuid4()), "host": host.id, {"id": str(uuid.uuid4()), "host": host.id,
"hash": hashlib.sha256(token.encode()).hexdigest()}) "hash": hashlib.sha256(token.encode()).hexdigest()})
s.add(PluginMetric(source_module="host_agent", resource_name=hostname, await record_metrics(s, [PluginMetric(source_module="host_agent", resource_name=hostname,
metric_name="cpu_pct", value=5.0)) metric_name="cpu_pct", value=5.0)])
await s.flush() await s.flush()
fields = await alert_svc.rule_fields( fields = await alert_svc.rule_fields(
s, name=f"cpu {tag}", source_module="host_agent", resource_name=hostname, s, name=f"cpu {tag}", source_module="host_agent", resource_name=hostname,
+4 -2
View File
@@ -124,6 +124,7 @@ def test_a_renamed_host_carries_agent_and_container_metrics_and_their_rules(app)
from sqlalchemy import select from sqlalchemy import select
from steward.alerts import service as alert_svc from steward.alerts import service as alert_svc
from steward.models.alerts import AlertRule from steward.models.alerts import AlertRule
from steward.core.alerts import record_metrics
from steward.models.hosts import Host from steward.models.hosts import Host
from steward.models.metrics import PluginMetric from steward.models.metrics import PluginMetric
@@ -140,8 +141,9 @@ def test_a_renamed_host_carries_agent_and_container_metrics_and_their_rules(app)
async with s.begin(): async with s.begin():
s.add(Host(id=hid, name=old, address="10.8.8.8")) s.add(Host(id=hid, name=old, address="10.8.8.8"))
s.add(Host(id=str(uuid.uuid4()), name=f"{old}x", address="10.8.8.9")) s.add(Host(id=str(uuid.uuid4()), name=f"{old}x", address="10.8.8.9"))
for src, res in rows: await record_metrics(s, [PluginMetric(source_module=src, resource_name=res,
s.add(PluginMetric(source_module=src, resource_name=res, metric_name="disk_used_pct", value=1)) metric_name="disk_used_pct", value=1)
for src, res in rows])
await s.flush() await s.flush()
fields = await alert_svc.rule_fields( fields = await alert_svc.rule_fields(
s, name=f"disk {tag}", source_module="host_agent", resource_name=f"{old}:/", s, name=f"disk {tag}", source_module="host_agent", resource_name=f"{old}:/",