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:
1 parent
d1eb87ba25
commit
2b1e36634a
53 files changed
+4254
-636
No files matched your search
@@ -0,0 +1,142 @@
|
||||
"""Kontaktverlust beendet einen Druck nicht."""
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from grotti.watcher import StateWatcher, contact_gap_keeps_run
|
||||
|
||||
HOST = "10.10.1.88"
|
||||
FILE = "boden_PETG_0.2_2h15m.gcode"
|
||||
|
||||
|
||||
class ContactGapTests(unittest.TestCase):
|
||||
def test_same_file_stays(self):
|
||||
self.assertTrue(contact_gap_keeps_run(FILE, FILE, "printing"))
|
||||
self.assertTrue(contact_gap_keeps_run(FILE, FILE, "paused"))
|
||||
|
||||
def test_other_file_does_not_stay(self):
|
||||
self.assertFalse(contact_gap_keeps_run(FILE, "andere.gcode", "printing"))
|
||||
|
||||
def test_terminal_state_does_not_stay(self):
|
||||
self.assertFalse(contact_gap_keeps_run(FILE, FILE, "standby"))
|
||||
self.assertFalse(contact_gap_keeps_run(FILE, FILE, "complete"))
|
||||
self.assertFalse(contact_gap_keeps_run(FILE, FILE, "error"))
|
||||
|
||||
def test_missing_name_is_not_a_change(self):
|
||||
self.assertTrue(contact_gap_keeps_run("", FILE, "printing"))
|
||||
self.assertTrue(contact_gap_keeps_run(FILE, "", "paused"))
|
||||
|
||||
|
||||
class WatcherOfflineTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.watcher = StateWatcher("postgresql://x", {})
|
||||
self.watcher._prev[HOST] = {
|
||||
"state": "printing",
|
||||
"offline": False,
|
||||
"filename": FILE,
|
||||
"run_id": 42,
|
||||
}
|
||||
|
||||
def test_two_misses_keep_the_run(self):
|
||||
live = {
|
||||
"host": HOST,
|
||||
"name": "Kobra S1",
|
||||
"state": "offline",
|
||||
"ok": False,
|
||||
"filename": "",
|
||||
}
|
||||
with mock.patch.object(self.watcher, "_emit") as emit, \
|
||||
mock.patch("grotti.watcher.store.complete_open_run") as close, \
|
||||
mock.patch("grotti.watcher.jobs.apply_deduction") as deduct:
|
||||
self.watcher._one(mock.Mock(), live)
|
||||
self.watcher._one(mock.Mock(), live)
|
||||
close.assert_not_called()
|
||||
deduct.assert_not_called()
|
||||
remembered = self.watcher._prev[HOST]
|
||||
self.assertEqual(remembered["state"], "printing")
|
||||
self.assertTrue(remembered["offline"])
|
||||
self.assertEqual(remembered["run_id"], 42)
|
||||
self.assertEqual(remembered["filename"], FILE)
|
||||
self.assertEqual([call.args[3] for call in emit.call_args_list], ["offline"])
|
||||
|
||||
def test_same_print_after_gap_is_the_same_run(self):
|
||||
self.watcher._prev[HOST]["offline"] = True
|
||||
live = {
|
||||
"host": HOST,
|
||||
"name": "Kobra S1",
|
||||
"state": "printing",
|
||||
"ok": True,
|
||||
"filename": FILE,
|
||||
"weight": 0,
|
||||
}
|
||||
run = {"id": 42, "filename": FILE}
|
||||
with mock.patch.object(self.watcher, "_emit") as emit, \
|
||||
mock.patch.object(self.watcher, "_track_print", return_value=run) as track, \
|
||||
mock.patch.object(self.watcher, "_check_spool", return_value=False), \
|
||||
mock.patch("grotti.watcher.store.find_live_run", return_value=run), \
|
||||
mock.patch("grotti.watcher.store.abandon_live_runs") as abandon, \
|
||||
mock.patch("grotti.watcher.store.complete_open_run") as close, \
|
||||
mock.patch("grotti.watcher.jobs.sync_history") as sync, \
|
||||
mock.patch("grotti.watcher.jobs.apply_deduction") as deduct:
|
||||
self.watcher._one(mock.Mock(), live)
|
||||
close.assert_not_called()
|
||||
deduct.assert_not_called()
|
||||
abandon.assert_not_called()
|
||||
sync.assert_not_called()
|
||||
track.assert_called_once()
|
||||
self.assertEqual([call.args[3] for call in emit.call_args_list], ["offline"])
|
||||
self.assertIn("wieder erreichbar", emit.call_args_list[0].args[4])
|
||||
self.assertEqual(self.watcher._prev[HOST]["state"], "printing")
|
||||
self.assertFalse(self.watcher._prev[HOST]["offline"])
|
||||
|
||||
def test_standby_after_gap_closes(self):
|
||||
self.watcher._prev[HOST]["offline"] = True
|
||||
live = {
|
||||
"host": HOST,
|
||||
"name": "Kobra S1",
|
||||
"state": "standby",
|
||||
"ok": True,
|
||||
"filename": "",
|
||||
}
|
||||
run = {"id": 42, "filename": FILE}
|
||||
with mock.patch.object(self.watcher, "_emit") as emit, \
|
||||
mock.patch.object(self.watcher, "_track_print", return_value=None), \
|
||||
mock.patch.object(self.watcher, "_check_spool", return_value=False), \
|
||||
mock.patch("grotti.watcher.store.find_live_run", return_value=run), \
|
||||
mock.patch("grotti.watcher.store.running_print_on_host", return_value=None), \
|
||||
mock.patch("grotti.watcher.store.abandon_live_runs") as abandon, \
|
||||
mock.patch("grotti.watcher.store.set_bed_needs_clear"), \
|
||||
mock.patch("grotti.watcher.jobs.sync_history") as sync:
|
||||
self.watcher._one(mock.Mock(), live)
|
||||
abandon.assert_called_once()
|
||||
sync.assert_called_once()
|
||||
self.assertIn("abbruch", [call.args[3] for call in emit.call_args_list])
|
||||
|
||||
def test_other_file_after_gap_releases_the_old_run(self):
|
||||
self.watcher._prev[HOST]["offline"] = True
|
||||
live = {
|
||||
"host": HOST,
|
||||
"name": "Kobra S1",
|
||||
"state": "printing",
|
||||
"ok": True,
|
||||
"filename": "andere.gcode",
|
||||
"weight": 0,
|
||||
}
|
||||
old = {"id": 42, "filename": FILE}
|
||||
new = {"id": 99, "filename": "andere.gcode"}
|
||||
with mock.patch.object(self.watcher, "_emit") as emit, \
|
||||
mock.patch.object(self.watcher, "_track_print", return_value=new), \
|
||||
mock.patch.object(self.watcher, "_ensure_start_segment"), \
|
||||
mock.patch.object(self.watcher, "_check_spool", return_value=False), \
|
||||
mock.patch("grotti.watcher.store.find_live_run", side_effect=[old, old, None]), \
|
||||
mock.patch("grotti.watcher.store.abandon_live_runs") as abandon, \
|
||||
mock.patch("grotti.watcher.jobs.sync_history") as sync:
|
||||
self.watcher._one(mock.Mock(), live)
|
||||
sync.assert_called_once()
|
||||
self.assertGreaterEqual(abandon.call_count, 1)
|
||||
kinds = [call.args[3] for call in emit.call_args_list]
|
||||
self.assertEqual(kinds, ["abbruch", "offline", "start"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user