Multiple printers, printer/slot in Spoolman, kept in sync
CI / test (push) Successful in 1m6s
CI / image (push) Successful in 43s

- One worker per printer (name, IP, CC2 Control URL, own pinned host key);
  a spool sits in at most one slot of one printer, moves between printers
- Spoolman: location "<printer> Slot N" plus extra fields "drucker"/"slot"
  (created by the bridge), cleared and "Lager" on removal
- Full comparison every minute: the printer wins over manual edits of loaded
  spools; stale printer locations go to storage; own locations untouched
- Automatic migration of v1 settings, state and host key
- Status hint when a tag is still in a tray but unmapped (e.g. after
  "Take out" in CC2 Control)
- SSH test: connection drops during exec give a clean error, not a 500
- Mock environment with several printers; tests for all of the above

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014GcEk5tkfFSYD6NTF66NkC
This commit is contained in:
Jonas MenzelandClaude Opus 5.5 committed 2026-10-25 03:53:01 +01:00
1 parent bf32667f77
commit a9041eb538
15 files changed
+1400 -684

No files matched your search

+21 -5
View File
@@ -67,8 +67,9 @@ def test_ssh_key_upload_never_returned(tmp_path):
def test_hostkey_only_from_last_test(tmp_path):
c, _ = make_client(tmp_path)
r = c.post("/api/ssh/hostkey", json={"fingerprint": "SHA256:forged"}, headers=H)
r = c.post("/api/printers/p1/ssh/hostkey", json={"fingerprint": "SHA256:forged"}, headers=H)
assert r.status_code == 400
assert c.post("/api/printers/nope/ssh/hostkey", json={"fingerprint": "x"}, headers=H).status_code == 404
def test_tag_endpoint(tmp_path):
@@ -104,7 +105,22 @@ def test_status_and_commands(tmp_path):
c, bridge = make_client(tmp_path)
bridge.poll_once()
st = c.get("/api/status").json()
assert len(st["slots"]) == 4 and st["dry_run"] is True
assert c.post("/api/cc2/enable", json={}, headers=H).status_code == 400
assert c.post("/api/cc2/enable", json={"confirm": True}, headers=H).json()["dry_run"] is True
assert c.post("/api/slots/7/release", headers=H).status_code == 404
assert len(st["printers"]) == 1 and len(st["printers"][0]["slots"]) == 4 and st["dry_run"] is True
assert c.post("/api/printers/p1/cc2/enable", json={}, headers=H).status_code == 400
assert c.post("/api/printers/p1/cc2/enable", json={"confirm": True}, headers=H).json()["dry_run"] is True
assert c.post("/api/printers/p1/slots/7/release", headers=H).status_code == 404
assert c.post("/api/printers/zz/slots/1/release", headers=H).status_code == 404
def test_printers_editable(tmp_path):
c, _ = make_client(tmp_path)
s = c.get("/api/settings").json()
printers = s["printers"] + [{"name": "Links", "host": "10.10.2.235", "cc2_url": "http://10.10.2.235:8081"}]
r = c.post("/api/settings", json={"printers": printers}, headers=H)
assert r.status_code == 200
got = r.json()["printers"]
assert [p["name"] for p in got] == ["CC2", "Links"] and got[1]["id"].startswith("p") and got[1]["ssh_port"] == 22
dup = c.post("/api/settings", json={"printers": got + [{"name": "links", "host": "x", "cc2_url": "http://x"}]}, headers=H)
assert dup.status_code == 400
bad = c.post("/api/settings", json={"location_slot": "Slot {n}"}, headers=H)
assert bad.status_code == 400 # two printers need {printer}