""" Tests für buried/report — das druckerseitige Analytics-Event, das einmal pro Druckstart feuert (verifiziert live gegen einen echten Kobra X, sowohl für Anycubic Slicer Next als auch für OrcaSlicer/die Bridge selbst). Liefert gcode_size/estimate_duration/total_layers, die server/files/metadata für Dateien außerhalb des eigenen GCodeStore sonst nicht hat (Issue #102). """ import pytest BURIED_PAYLOAD = { "type": "buried", "action": "PrintStart", "code": 200, "state": "done", "data": { "task_name": "Smileys_simple_plate(01)_PLA_0.2_16m39s.gcode", "gcode_size": 644437, "estimate_duration": 1264, "total_layers": 8, "storage_total": 6481, "storage_used": 898, "slicer": "OrcaSlicer", }, } def test_on_buried_populates_cache(client): _, bridge = client bridge._on_buried(BURIED_PAYLOAD) assert bridge._buried_cache == { "task_name": "Smileys_simple_plate(01)_PLA_0.2_16m39s.gcode", "gcode_size": 644437, "estimate_duration": 1264, "total_layers": 8, } def test_on_buried_populates_storage_state(client): _, bridge = client bridge._on_buried(BURIED_PAYLOAD) assert bridge._state["storage_total_mb"] == 6481 assert bridge._state["storage_used_mb"] == 898 def test_on_buried_ignores_payload_without_task_name(client): _, bridge = client bridge._buried_cache = None bridge._on_buried({"type": "buried", "data": {"gcode_size": 123}}) assert bridge._buried_cache is None def test_build_file_metadata_uses_buried_fallback_for_unknown_file(client): """A file not in the GCodeStore and not the currently-tracked job should still get real size/estimated_time/layer_count from the buried cache.""" _, bridge = client bridge._on_buried(BURIED_PAYLOAD) meta = bridge._build_file_metadata("Smileys_simple_plate(01)_PLA_0.2_16m39s.gcode") assert meta["size"] == 644437 assert meta["estimated_time"] == 1264 assert meta["layer_count"] == 8 def test_build_file_metadata_ignores_buried_cache_for_different_file(client): """The buried cache must only apply when task_name matches the queried filename - otherwise it would leak the last print's data into an unrelated query, the exact bug Issue #102 already fixed for live state.""" _, bridge = client bridge._on_buried(BURIED_PAYLOAD) meta = bridge._build_file_metadata("some_other_file.gcode") assert meta["size"] == 1 # unchanged fallback, not leaked from buried cache assert meta["estimated_time"] is None assert meta["layer_count"] is None def test_build_file_metadata_prefers_gcodestore_over_buried(client): """GCodeStore data (from the bridge's own upload) must win over the buried cache when both are available for the same filename.""" _, bridge = client bridge._on_buried(BURIED_PAYLOAD) with bridge._store._lock: bridge._store._conn.execute( "INSERT INTO gcode_files (id, filename, path, size_bytes, uploaded_at, layer_count, est_print_time_sec) " "VALUES (?,?,?,?,?,?,?)", ("f1", "Smileys_simple_plate(01)_PLA_0.2_16m39s.gcode", "/tmp/f1", 999999, "2026-01-01T00:00:00Z", 42, 5000), ) bridge._store._conn.commit() meta = bridge._build_file_metadata("Smileys_simple_plate(01)_PLA_0.2_16m39s.gcode") assert meta["size"] == 999999 assert meta["estimated_time"] == 5000 assert meta["layer_count"] == 42 @pytest.mark.asyncio async def test_api_state_reports_storage_after_buried_report(client): c, bridge = client bridge._on_buried(BURIED_PAYLOAD) resp = await c.get("/api/state") assert resp.status == 200 data = await resp.json() assert data["storage_total_mb"] == 6481 assert data["storage_used_mb"] == 898 @pytest.mark.asyncio async def test_api_state_storage_defaults_to_zero(client): c, _ = client resp = await c.get("/api/state") data = await resp.json() assert data["storage_total_mb"] == 0 assert data["storage_used_mb"] == 0