Scroll the runs table, pick a range, and choose what a comparison plots against
Docs / docs (push) Successful in 35s
Playwright Tests / test-playwright (1, 2) (push) Failing after 3m14s
Playwright Tests / test-playwright (2, 2) (push) Failing after 1m44s
pre-commit / pre-commit (push) Failing after 3m54s
Test Backend / test-backend (push) Successful in 3m12s
Compose Smoke Test / test-compose (push) Successful in 32s
Playwright Tests / merge-reports (push) Failing after 1m28s

This commit is contained in:
2026-08-25 16:32:34 +02:00
parent 3c15964364
commit 4350916bd8
14 changed files with 498 additions and 151 deletions
+83 -1
View File
@@ -8,7 +8,7 @@ import json
from datetime import UTC, datetime
import pytest
from sqlmodel import Session, select
from sqlmodel import Session, col, select
from fluksio.core.config import settings
from fluksio.core.db import engine as db_engine
@@ -380,3 +380,85 @@ def test_a_curve_whose_run_is_gone_is_empty_rather_than_an_error(
)
assert answer.status_code == 200
assert answer.json() == []
def _metric(run_id: str, name: str, step: int, value: float, ts: float) -> RunMetric:
return RunMetric(run_id=run_id, name=name, step=step, value=value, ts=ts)
@pytest.fixture
def plotted():
"""A run with a loss curve and an epoch counter beside it."""
run_id = new_run_id()
with Session(db_engine) as session:
session.add(
Run(id=run_id, flow="study", status="ok", created_at=datetime.now(UTC))
)
for step, (loss, epoch) in enumerate([(1.0, 10.0), (0.5, 20.0), (0.25, 30.0)]):
session.add(_metric(run_id, "study.loss", step, loss, 100.0 + step * 5))
session.add(_metric(run_id, "study.epoch", step, epoch, 100.0 + step * 5))
session.commit()
yield run_id
with Session(db_engine) as session:
for row in session.exec(
select(RunMetric).where(col(RunMetric.run_id) == run_id)
).all():
session.delete(row)
session.delete(session.get(Run, run_id))
session.commit()
def test_a_comparison_is_plotted_against_the_step_by_default(
client, superuser_token_headers, plotted
):
answer = client.get(
f"{settings.API_V1_STR}/runs/series/compare",
params={"ids": plotted, "metric": "study.loss"},
headers=superuser_token_headers,
).json()
assert answer["x"] == "step"
assert answer["lines"][0]["points"] == [[0.0, 1.0], [1.0, 0.5], [2.0, 0.25]]
def test_time_is_measured_from_this_runs_own_first_reading(
client, superuser_token_headers, plotted
):
"""Runs started hours apart still lie on top of each other."""
answer = client.get(
f"{settings.API_V1_STR}/runs/series/compare",
params={"ids": plotted, "metric": "study.loss", "x": "time"},
headers=superuser_token_headers,
).json()
assert answer["x"] == "time"
assert answer["lines"][0]["points"] == [[0.0, 1.0], [5.0, 0.5], [10.0, 0.25]]
def test_one_metric_can_be_plotted_against_another(
client, superuser_token_headers, plotted
):
answer = client.get(
f"{settings.API_V1_STR}/runs/series/compare",
params={"ids": plotted, "metric": "study.loss", "x": "study.epoch"},
headers=superuser_token_headers,
).json()
assert answer["lines"][0]["points"] == [[10.0, 1.0], [20.0, 0.5], [30.0, 0.25]]
def test_a_step_the_x_metric_never_reached_is_left_out(
client, superuser_token_headers, plotted
):
"""The join is on the step, which is the only thing two series share."""
with Session(db_engine) as session:
session.add(_metric(plotted, "study.loss", 3, 0.1, 120.0))
session.commit()
answer = client.get(
f"{settings.API_V1_STR}/runs/series/compare",
params={"ids": plotted, "metric": "study.loss", "x": "study.epoch"},
headers=superuser_token_headers,
).json()
assert [point[0] for point in answer["lines"][0]["points"]] == [10.0, 20.0, 30.0]