diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_k1c.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/tests/test_k1c.py b/tests/test_k1c.py new file mode 100644 index 0000000..b82869e --- /dev/null +++ b/tests/test_k1c.py @@ -0,0 +1,108 @@ +# deck-it - tests for the K1C printer module +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + +import unittest + +import deckit.modules.k1c as k1c + +URL = "http://printer.example.org:7125" +STATUS = { + "webhooks": {"state": "ready", "state_message": "Printer is ready"}, + "print_stats": {"state": "printing", "filename": "part.gcode", "print_duration": 600.0, + "filament_used": 1234.5, "info": {"current_layer": 12, "total_layer": 80}}, + "virtual_sdcard": {"progress": 0.25}, + "extruder": {"temperature": 219.8, "target": 220.0, "power": 0.4}, + "heater_bed": {"temperature": 60.1, "target": 60.0, "power": 0.2}, + "fan": {"speed": 1.0}, + "toolhead": {"position": [10.0, 20.0, 3.2, 100.0]}, + "gcode_move": {"speed_factor": 1.0}, +} +CAMS = {"result": {"webcams": [{"enabled": True, "snapshot_url": "http://printer.example.org:8080/?action=snapshot"}]}} + + +class Fake: + def __init__(self, down=False): + self.calls, self.down = [], down + + def __call__(self, url, data=None, timeout=2): + self.calls.append((url, data)) + if self.down: + raise OSError("connection refused") + if url.endswith("/server/webcams/list"): + return CAMS + if "/server/files/metadata" in url: + return {"result": {"estimated_time": 2700, "thumbnails": [ + {"width": 32, "height": 32, "relative_path": ".thumbs/part-32x32.png"}, + {"width": 300, "height": 300, "relative_path": ".thumbs/part-300x300.png"}]}} + if url.endswith("/printer/emergency_stop"): + return {"result": "ok"} + return {"result": {"status": STATUS}} + + +class K1C(unittest.TestCase): + def test_summarizes_a_print(self): + st = k1c.make({"k1c": {"url": URL}, "http": Fake()}).state() + self.assertEqual(st["state"], "printing") + self.assertEqual(st["remaining"], 1800.0) # 600s for 25%: 1800s to go + self.assertEqual((st["layer"], st["layers"]), (12, 80)) + self.assertEqual(st["extruder"]["target"], 220.0) + self.assertEqual(st["position"], [10.0, 20.0, 3.2]) + self.assertTrue(st["snapshot"].endswith("action=snapshot")) + self.assertEqual(st["thumbnail"], URL + "/server/files/gcodes/.thumbs/part-300x300.png") + + def test_thumbnail_is_relative_to_the_file_and_quoted(self): + url = k1c._thumbnail(URL, "jobs/my part.gcode", {"thumbnails": [{"width": 9, "height": 9, + "relative_path": ".thumbs/my part-9x9.png"}]}) + self.assertEqual(url, URL + "/server/files/gcodes/jobs/.thumbs/my%20part-9x9.png") + self.assertIsNone(k1c._thumbnail(URL, "x.gcode", {})) + + def test_metadata_is_fetched_once_per_file(self): + fake = Fake() + m = k1c.make({"k1c": {"url": URL}, "http": fake}) + m.state(), m.state() + self.assertEqual(sum("/server/files/metadata" in u for u, _ in fake.calls), 1) + + def test_off_backs_off_instead_of_polling_every_tick(self): + fake = Fake(down=True) + m = k1c.make({"k1c": {"url": URL}, "http": fake}) + self.assertTrue(m.state()["offline"]) + self.assertTrue(m.state()["offline"]) + self.assertEqual(len(fake.calls), 1) + + def test_unconfigured(self): + self.assertTrue(k1c.make({}).state()["unconfigured"]) + + def test_emergency_stop_posts_m112(self): + fake = Fake() + k1c.make({"k1c": {"url": URL}, "http": fake}).actions["emergency_stop"]({}) + self.assertEqual(fake.calls, [(URL + "/printer/emergency_stop", b"")]) + + def test_emergency_stop_failure_is_reported(self): + m = k1c.make({"k1c": {"url": URL}, "http": Fake(down=True)}) + with self.assertRaises(k1c.ModuleError): + m.actions["emergency_stop"]({}) + + def test_snapshot_needs_http(self): + self.assertIsNone(k1c._snapshot([{"snapshot_url": "javascript:alert(1)"}])) + + +if __name__ == "__main__": + unittest.main() |
