|
|
@@ -0,0 +1,112 @@
|
|
|
+"""Statistics keeps naming a printer that was deleted with its history (#2873).
|
|
|
+
|
|
|
+Deleting a printer while keeping its prints leaves the log rows pointing at an
|
|
|
+id nothing resolves any more, so every per-printer breakdown fell back to
|
|
|
+"Printer 1" for machines the reporter knew as "Ultron". Each run recorded the
|
|
|
+name it printed on, so that is what the aggregates report now.
|
|
|
+"""
|
|
|
+
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
+from datetime import datetime, timedelta
|
|
|
+
|
|
|
+import pytest
|
|
|
+from httpx import AsyncClient
|
|
|
+
|
|
|
+from backend.app.models.print_log import PrintLogEntry
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+@pytest.mark.integration
|
|
|
+async def test_stats_name_history_of_a_deleted_printer(async_client: AsyncClient, db_session):
|
|
|
+ base = datetime(2026, 7, 15, 10, 0, 0)
|
|
|
+ db_session.add_all(
|
|
|
+ [
|
|
|
+ PrintLogEntry(
|
|
|
+ printer_id=71,
|
|
|
+ printer_name="Ultron",
|
|
|
+ status="completed",
|
|
|
+ started_at=base,
|
|
|
+ completed_at=base + timedelta(hours=1),
|
|
|
+ duration_seconds=3600,
|
|
|
+ ),
|
|
|
+ PrintLogEntry(
|
|
|
+ printer_id=71,
|
|
|
+ printer_name="Ultron",
|
|
|
+ status="failed",
|
|
|
+ started_at=base + timedelta(hours=2),
|
|
|
+ completed_at=base + timedelta(hours=3),
|
|
|
+ duration_seconds=3600,
|
|
|
+ ),
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ await db_session.commit()
|
|
|
+
|
|
|
+ stats = (await async_client.get("/api/v1/archives/stats")).json()
|
|
|
+
|
|
|
+ assert stats["prints_by_printer"]["71"] == 2
|
|
|
+ assert stats["printer_names"]["71"] == "Ultron"
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+@pytest.mark.integration
|
|
|
+async def test_stats_reports_the_last_name_the_printer_ran_under(async_client: AsyncClient, db_session):
|
|
|
+ """A printer renamed before it was deleted is remembered by its last name."""
|
|
|
+ base = datetime(2026, 7, 15, 10, 0, 0)
|
|
|
+ db_session.add_all(
|
|
|
+ [
|
|
|
+ PrintLogEntry(printer_id=71, printer_name="Ultron", status="completed", started_at=base),
|
|
|
+ PrintLogEntry(
|
|
|
+ printer_id=71,
|
|
|
+ printer_name="Ultron Mk II",
|
|
|
+ status="completed",
|
|
|
+ started_at=base + timedelta(days=1),
|
|
|
+ ),
|
|
|
+ # A run logged before names were recorded must not blank the label.
|
|
|
+ PrintLogEntry(printer_id=71, printer_name=None, status="completed", started_at=base + timedelta(days=2)),
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ await db_session.commit()
|
|
|
+
|
|
|
+ stats = (await async_client.get("/api/v1/archives/stats")).json()
|
|
|
+
|
|
|
+ assert stats["printer_names"]["71"] == "Ultron Mk II"
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+@pytest.mark.integration
|
|
|
+async def test_stats_names_do_not_override_a_live_printer(async_client: AsyncClient, db_session, printer_factory):
|
|
|
+ """Renaming a printer that still exists shows up straight away.
|
|
|
+
|
|
|
+ The client prefers the live record, so the historical name only has to be
|
|
|
+ present, not authoritative.
|
|
|
+ """
|
|
|
+ printer = await printer_factory(name="Renamed Later")
|
|
|
+ db_session.add(PrintLogEntry(printer_id=printer.id, printer_name="Original Name", status="completed"))
|
|
|
+ await db_session.commit()
|
|
|
+
|
|
|
+ stats = (await async_client.get("/api/v1/archives/stats")).json()
|
|
|
+ printers = (await async_client.get("/api/v1/printers/")).json()
|
|
|
+
|
|
|
+ assert stats["printer_names"][str(printer.id)] == "Original Name"
|
|
|
+ assert [p["name"] for p in printers if p["id"] == printer.id] == ["Renamed Later"]
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+@pytest.mark.integration
|
|
|
+async def test_failure_analysis_names_a_deleted_printer(async_client: AsyncClient, db_session, printer_factory):
|
|
|
+ """Failures by printer reads the recorded name once the printer is gone."""
|
|
|
+ live = await printer_factory(name="Still Here")
|
|
|
+ db_session.add_all(
|
|
|
+ [
|
|
|
+ PrintLogEntry(printer_id=71, printer_name="Ultron", status="failed"),
|
|
|
+ PrintLogEntry(printer_id=live.id, printer_name="Older Name", status="failed"),
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ await db_session.commit()
|
|
|
+
|
|
|
+ analysis = (await async_client.get("/api/v1/archives/analysis/failures")).json()
|
|
|
+
|
|
|
+ assert analysis["failures_by_printer"]["Ultron"] == 1
|
|
|
+ assert analysis["failures_by_printer"]["Still Here"] == 1
|
|
|
+ assert "Printer 71" not in analysis["failures_by_printer"]
|