Grotti 3.6.0: Lauf-Identität nach Filament-Pause, robustere Queue, Projekte/Aufträge list-first und API-Polish.

This commit is contained in:
Dominic Gundel committed 2026-10-25 08:24:24 +01:00
1 parent d1eb87ba25
commit 2b1e36634a
53 files changed
+4254 -636

No files matched your search

+79
View File
@@ -0,0 +1,79 @@
"""Szenarien für einen physischen Druck = ein Lauf (ohne DB, mit Mocks)."""
import os
import unittest
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock, patch
from grotti import jobs
class SyncOneJobShellTests(unittest.TestCase):
def test_empty_shell_skipped(self):
conn = MagicMock()
printer = {"host": "h", "name": "P"}
job = {
"job_id": "000041",
"filename": "a.gcode",
"status": "in_progress",
"start_time": 1000,
"end_time": None,
"print_duration": 0,
"total_duration": 0,
"metadata": {},
}
self.assertEqual(jobs._sync_one_job(conn, {"energy": {}}, printer, job), 0)
conn.execute.assert_not_called()
class FoldProofIntegrationLike(unittest.TestCase):
def test_fold_requires_duration_proof(self):
end = datetime(2026, 10, 25, 5, 48, 27, tzinfo=timezone.utc)
start = end + timedelta(milliseconds=40)
pred = {
"id": 1,
"ended_at": end,
"duration_s": 11711,
"moonraker_job_id": "000040",
"verdict": "",
}
conn = MagicMock()
conn.execute.return_value.fetchone.return_value = None
with patch("grotti.jobs.store.find_resume_predecessor", return_value=pred), \
patch("grotti.jobs.store.remember_run_job"), \
patch("grotti.jobs.store.move_run_jobs"), \
patch("grotti.jobs.store.set_printer_active_run"), \
patch("grotti.jobs.undo_deduction"):
# Frischer Neustart (Dauer 12) — kein Fold
self.assertIsNone(jobs.fold_filament_resume(
conn, "h", "a.gcode", "000041", start, print_duration_s=12
))
# Fortgesetzte Dauer — Fold
self.assertEqual(
jobs.fold_filament_resume(
conn, "h", "a.gcode", "000041", start, print_duration_s=11711
),
1,
)
@unittest.skipUnless(os.environ.get("GROTTI_TEST_DB"), "GROTTI_TEST_DB nicht gesetzt")
class LiveDbScenarios(unittest.TestCase):
"""Gegen echte Test-DB: GROTTI_TEST_DB=postgresql://…"""
def setUp(self):
import psycopg
from psycopg.rows import dict_row
self.conn = psycopg.connect(os.environ["GROTTI_TEST_DB"], row_factory=dict_row)
def tearDown(self):
self.conn.rollback()
self.conn.close()
def test_connection(self):
self.assertTrue(self.conn.execute("SELECT 1").fetchone())
if __name__ == "__main__":
unittest.main()