Files
app/backend/tests/flow/test_device_store.py
T
Melvin StroblandClaude Opus 5.5 ed06bdec6b Panels become devices: per-device documents in the flow repo, a Devices tab
- flow/devices.py: DeviceDef in FLOWS_DIR/_devices/<id>.json, committed under
  the flow store's write lock, 409 on a stale version; nonces in DEVICES_FILE
  outside git; in-memory presence announced as device_status
- api/routes/devices.py: CRUD, pairing with an optional {name, board,
  firmware}, a pending list adopted without a code from the LAN only, unpair;
  /panels/pair, /panels/pair/{code} and GET /panels/{id} kept as aliases,
  PUT /panels/ gone
- _device_may replaces _panel_may, JWT claims unchanged
- panels.json moves into devices once at startup, then .migrated
- MCP list_devices, get_device; search category device
- Devices tab (list, detail with presence, pairing, ordered dashboards,
  touch, I/O), PanelsDialog removed, serialised optimistic saves

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:48:36 +02:00

59 lines
2.0 KiB
Python

"""The one-time move of an older instance's panels file into devices."""
import json
import subprocess
from pathlib import Path
from fluksio.flow.devices import DeviceStore
from fluksio.flow.store import FlowStore
def test_panels_move_into_devices_once(tmp_path: Path) -> None:
flows = FlowStore(tmp_path / "flows")
panels = tmp_path / "panels.json"
panels.write_text(
json.dumps(
{
"panels": [
{"id": "hall", "title": "Hall", "dashboards": ["home"], "nonce": 2},
{"id": "knob", "touch": True, "io": [], "nonce": 0},
],
"version": 7,
}
)
)
store = DeviceStore(flows, tmp_path / "devices.json")
store.migrate(panels)
assert not panels.exists()
assert (tmp_path / "panels.json.migrated").exists()
hall = store.find("hall")
assert hall is not None and hall.dashboards == ["home"] and hall.version == 1
assert store.find("knob").touch is True # type: ignore[union-attr]
# The nonce stays outside git, so a credential minted at it still stands.
assert store.nonce("hall") == 2
assert "nonce" not in (flows.root / "_devices" / "hall.json").read_text()
log = subprocess.run(
["git", "-C", str(flows.root), "log", "--format=%s"],
capture_output=True,
text=True,
).stdout
assert log.splitlines()[0] == "Migrate panels to devices"
# Nothing in `_devices` is taken for a flow.
assert flows.list_flows() == []
# A second start finds nothing to do, and a panels file restored from a
# backup does not lower a nonce an unpair has raised since.
store.bump("hall")
panels.write_text((tmp_path / "panels.json.migrated").read_text())
store.migrate(panels)
assert store.nonce("hall") == 3
assert (
log
== subprocess.run(
["git", "-C", str(flows.root), "log", "--format=%s"],
capture_output=True,
text=True,
).stdout
)