fix: update test fixtures for SQLite storage migration
Some checks failed
Lint & Test / test (push) Failing after 1m33s

All store tests were passing file paths instead of Database objects
after the JSON-to-SQLite migration. Updated fixtures to create temp
Database instances, rewrote backup e2e tests for binary .db format,
and fixed config tests for the simplified StorageConfig.
This commit is contained in:
2026-03-25 11:38:07 +03:00
parent 9dfd2365f4
commit 2da5c047f9
12 changed files with 135 additions and 126 deletions

View File

@@ -1,11 +1,9 @@
"""E2E: Backup and restore flow.
Tests creating entities, backing up, deleting, then restoring from backup.
Tests creating entities, backing up (SQLite .db file), deleting, then restoring.
"""
import io
import json
class TestBackupRestoreFlow:
@@ -42,20 +40,12 @@ class TestBackupRestoreFlow:
resp = client.get("/api/v1/color-strip-sources")
assert resp.json()["count"] == 1
# 2. Create a backup (GET returns a JSON file)
# 2. Create a backup (GET returns a SQLite .db file)
resp = client.get("/api/v1/system/backup")
assert resp.status_code == 200
backup_data = resp.json()
assert backup_data["meta"]["format"] == "ledgrab-backup"
assert "stores" in backup_data
assert "devices" in backup_data["stores"]
assert "color_strip_sources" in backup_data["stores"]
# Verify device is in the backup.
# Store files have structure: {"version": "...", "devices": {id: {...}}}
devices_store = backup_data["stores"]["devices"]
assert "devices" in devices_store
assert len(devices_store["devices"]) == 1
backup_bytes = resp.content
# SQLite files start with this magic header
assert backup_bytes[:16].startswith(b"SQLite format 3")
# 3. Delete all created entities
resp = client.delete(f"/api/v1/color-strip-sources/{css_id}")
@@ -69,52 +59,37 @@ class TestBackupRestoreFlow:
resp = client.get("/api/v1/color-strip-sources")
assert resp.json()["count"] == 0
# 4. Restore from backup (POST with the backup JSON as a file upload)
backup_bytes = json.dumps(backup_data).encode("utf-8")
# 4. Restore from backup (POST with the .db file upload)
resp = client.post(
"/api/v1/system/restore",
files={"file": ("backup.json", io.BytesIO(backup_bytes), "application/json")},
files={"file": ("backup.db", io.BytesIO(backup_bytes), "application/octet-stream")},
)
assert resp.status_code == 200, f"Restore failed: {resp.text}"
restore_result = resp.json()
assert restore_result["status"] == "restored"
assert restore_result["stores_written"] > 0
# 5. After restore, stores are written to disk but the in-memory
# stores haven't been re-loaded (normally a server restart does that).
# Verify the backup file was written correctly by reading it back.
# The restore endpoint writes JSON files; we check the response confirms success.
assert restore_result["restart_scheduled"] is True
def test_backup_contains_all_store_keys(self, client):
"""Backup response includes entries for all known store types."""
def test_backup_is_valid_sqlite(self, client):
"""Backup response is a valid SQLite database file."""
resp = client.get("/api/v1/system/backup")
assert resp.status_code == 200
stores = resp.json()["stores"]
# At minimum, these critical stores should be present
expected_keys = {
"devices", "output_targets", "color_strip_sources",
"capture_templates", "value_sources",
}
assert expected_keys.issubset(set(stores.keys()))
assert resp.content[:16].startswith(b"SQLite format 3")
# Should have Content-Disposition header for download
assert "attachment" in resp.headers.get("content-disposition", "")
def test_restore_rejects_invalid_format(self, client):
"""Uploading a non-backup JSON file should fail validation."""
bad_data = json.dumps({"not": "a backup"}).encode("utf-8")
"""Uploading a non-SQLite file should fail validation."""
bad_data = b"not a database file at all, just random text content"
resp = client.post(
"/api/v1/system/restore",
files={"file": ("bad.json", io.BytesIO(bad_data), "application/json")},
files={"file": ("bad.db", io.BytesIO(bad_data), "application/octet-stream")},
)
assert resp.status_code == 400
def test_restore_rejects_empty_stores(self, client):
"""A backup with no recognized stores should fail."""
bad_backup = {
"meta": {"format": "ledgrab-backup", "format_version": 1},
"stores": {"unknown_store": {}},
}
def test_restore_rejects_empty_file(self, client):
"""A tiny file should fail validation."""
resp = client.post(
"/api/v1/system/restore",
files={"file": ("bad.json", io.BytesIO(json.dumps(bad_backup).encode()), "application/json")},
files={"file": ("tiny.db", io.BytesIO(b"x" * 50), "application/octet-stream")},
)
assert resp.status_code == 400