#!/usr/bin/env python3 """A restore must not repoint this device at another machine's panel. display.hardware describes the panel physically wired to this device -- cols, rows, chain_length, hardware_mapping, panel_type, multiplexing, the refresh cap. A backup carries the panel of the machine it was taken on. Restoring a 512x64 rig's backup onto a 128x32 one used to overwrite the smaller panel's geometry with the larger one's, and nothing on screen explains why: the display just stops being right. That is not hypothetical. It happened, and the rig it happened to had to be reflashed. """ import json import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from src.backup_manager import _restore_config_preserving_hardware # noqa: E402 BIG = {"display": {"hardware": {"cols": 128, "rows": 64, "chain_length": 4, "hardware_mapping": "adafruit-hat-pwm"}, "runtime": {"gpio_slowdown": 4}}, "timezone": "America/New_York", "some-plugin": {"enabled": True}} SMALL = {"display": {"hardware": {"cols": 64, "rows": 32, "chain_length": 2, "hardware_mapping": "regular"}, "runtime": {"gpio_slowdown": 2}}, "timezone": "UTC"} def _run(tmp, keep): src = tmp / "backup_config.json"; src.write_text(json.dumps(BIG)) dst = tmp / "config.json"; dst.write_text(json.dumps(SMALL)) _restore_config_preserving_hardware(src, dst, keep_hardware=keep) return json.loads(dst.read_text()) def test_local_panel_survives(tmp_path): out = _run(tmp_path, keep=True) hw = out["display"]["hardware"] assert (hw["cols"], hw["rows"], hw["chain_length"]) == (64, 32, 2), ( "the restore repointed this device at the backup's panel") assert hw["hardware_mapping"] == "regular", "panel wiring came from the backup" def test_everything_else_is_restored(tmp_path): out = _run(tmp_path, keep=True) assert out["timezone"] == "America/New_York", "config was not restored" assert out["some-plugin"] == {"enabled": True}, "plugin config was not restored" assert out["display"]["runtime"] == {"gpio_slowdown": 4}, ( "only display.hardware should be held back") def test_opting_in_takes_the_backups_panel(tmp_path): out = _run(tmp_path, keep=False) hw = out["display"]["hardware"] assert (hw["cols"], hw["rows"], hw["chain_length"]) == (128, 64, 4) def test_a_device_with_no_local_hardware_takes_the_backups(tmp_path): src = tmp_path / "b.json"; src.write_text(json.dumps(BIG)) dst = tmp_path / "c.json"; dst.write_text(json.dumps({"timezone": "UTC"})) _restore_config_preserving_hardware(src, dst, keep_hardware=True) out = json.loads(dst.read_text()) assert out["display"]["hardware"]["cols"] == 128, ( "nothing local to preserve, so the backup's panel should be used") def test_unparseable_local_config_still_restores(tmp_path): src = tmp_path / "b.json"; src.write_text(json.dumps(BIG)) dst = tmp_path / "c.json"; dst.write_text("{ not json") _restore_config_preserving_hardware(src, dst, keep_hardware=True) assert json.loads(dst.read_text())["timezone"] == "America/New_York", ( "a restore must never fail because of this merge")