fix: update test fixtures for SQLite storage migration
Some checks failed
Lint & Test / test (push) Failing after 1m33s
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:
@@ -30,13 +30,21 @@ def _make_app():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_store(tmp_path):
|
||||
return DeviceStore(tmp_path / "devices.json")
|
||||
def _route_db(tmp_path):
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "test.db")
|
||||
yield db
|
||||
db.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def output_target_store(tmp_path):
|
||||
return OutputTargetStore(str(tmp_path / "output_targets.json"))
|
||||
def device_store(_route_db):
|
||||
return DeviceStore(_route_db)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def output_target_store(_route_db):
|
||||
return OutputTargetStore(_route_db)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -5,6 +5,7 @@ from datetime import datetime, timezone
|
||||
import pytest
|
||||
|
||||
from wled_controller.config import Config, StorageConfig, ServerConfig, AuthConfig
|
||||
from wled_controller.storage.database import Database
|
||||
from wled_controller.storage.device_store import Device, DeviceStore
|
||||
from wled_controller.storage.sync_clock import SyncClock
|
||||
from wled_controller.storage.sync_clock_store import SyncClockStore
|
||||
@@ -37,12 +38,25 @@ def test_config_dir(tmp_path):
|
||||
|
||||
@pytest.fixture
|
||||
def temp_store_dir(tmp_path):
|
||||
"""Provide a temp directory for JSON store files, cleaned up after tests."""
|
||||
"""Provide a temp directory for store files, cleaned up after tests."""
|
||||
d = tmp_path / "stores"
|
||||
d.mkdir(parents=True, exist_ok=True)
|
||||
return d
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Database fixture
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def tmp_db(tmp_path):
|
||||
"""Provide a temporary SQLite Database instance."""
|
||||
db = Database(tmp_path / "test.db")
|
||||
yield db
|
||||
db.close()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Config fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -55,20 +69,7 @@ def test_config(tmp_path):
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
storage = StorageConfig(
|
||||
devices_file=str(data_dir / "devices.json"),
|
||||
templates_file=str(data_dir / "capture_templates.json"),
|
||||
postprocessing_templates_file=str(data_dir / "postprocessing_templates.json"),
|
||||
picture_sources_file=str(data_dir / "picture_sources.json"),
|
||||
output_targets_file=str(data_dir / "output_targets.json"),
|
||||
pattern_templates_file=str(data_dir / "pattern_templates.json"),
|
||||
color_strip_sources_file=str(data_dir / "color_strip_sources.json"),
|
||||
audio_sources_file=str(data_dir / "audio_sources.json"),
|
||||
audio_templates_file=str(data_dir / "audio_templates.json"),
|
||||
value_sources_file=str(data_dir / "value_sources.json"),
|
||||
automations_file=str(data_dir / "automations.json"),
|
||||
scene_presets_file=str(data_dir / "scene_presets.json"),
|
||||
color_strip_processing_templates_file=str(data_dir / "color_strip_processing_templates.json"),
|
||||
sync_clocks_file=str(data_dir / "sync_clocks.json"),
|
||||
database_file=str(data_dir / "test.db"),
|
||||
)
|
||||
|
||||
return Config(
|
||||
@@ -84,33 +85,33 @@ def test_config(tmp_path):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_store(temp_store_dir):
|
||||
"""Provide a DeviceStore backed by a temp file."""
|
||||
return DeviceStore(temp_store_dir / "devices.json")
|
||||
def device_store(tmp_db):
|
||||
"""Provide a DeviceStore backed by a temp database."""
|
||||
return DeviceStore(tmp_db)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sync_clock_store(temp_store_dir):
|
||||
"""Provide a SyncClockStore backed by a temp file."""
|
||||
return SyncClockStore(str(temp_store_dir / "sync_clocks.json"))
|
||||
def sync_clock_store(tmp_db):
|
||||
"""Provide a SyncClockStore backed by a temp database."""
|
||||
return SyncClockStore(tmp_db)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def output_target_store(temp_store_dir):
|
||||
"""Provide an OutputTargetStore backed by a temp file."""
|
||||
return OutputTargetStore(str(temp_store_dir / "output_targets.json"))
|
||||
def output_target_store(tmp_db):
|
||||
"""Provide an OutputTargetStore backed by a temp database."""
|
||||
return OutputTargetStore(tmp_db)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def automation_store(temp_store_dir):
|
||||
"""Provide an AutomationStore backed by a temp file."""
|
||||
return AutomationStore(str(temp_store_dir / "automations.json"))
|
||||
def automation_store(tmp_db):
|
||||
"""Provide an AutomationStore backed by a temp database."""
|
||||
return AutomationStore(tmp_db)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def value_source_store(temp_store_dir):
|
||||
"""Provide a ValueSourceStore backed by a temp file."""
|
||||
return ValueSourceStore(str(temp_store_dir / "value_sources.json"))
|
||||
def value_source_store(tmp_db):
|
||||
"""Provide a ValueSourceStore backed by a temp database."""
|
||||
return ValueSourceStore(tmp_db)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -25,8 +25,8 @@ from wled_controller.storage.automation_store import AutomationStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_store(tmp_path) -> AutomationStore:
|
||||
return AutomationStore(str(tmp_path / "auto.json"))
|
||||
def mock_store(tmp_db) -> AutomationStore:
|
||||
return AutomationStore(tmp_db)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -46,10 +46,12 @@ def client(_test_client):
|
||||
|
||||
def _clear_stores():
|
||||
"""Remove all entities from all stores for test isolation."""
|
||||
# Reset the saves-frozen flag that freeze_saves() sets during restore flows.
|
||||
# Without this, subsequent tests can't persist data because _save() is a no-op.
|
||||
# Reset frozen-writes flags that restore flows set.
|
||||
# Without this, subsequent tests can't persist data.
|
||||
from wled_controller.storage.base_store import unfreeze_saves
|
||||
unfreeze_saves()
|
||||
import wled_controller.storage.database as _db_mod
|
||||
_db_mod._writes_frozen = False
|
||||
|
||||
from wled_controller.api import dependencies as deps
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,8 +18,8 @@ from wled_controller.storage.automation_store import AutomationStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store(tmp_path) -> AutomationStore:
|
||||
return AutomationStore(str(tmp_path / "automations.json"))
|
||||
def store(tmp_db) -> AutomationStore:
|
||||
return AutomationStore(tmp_db)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -240,16 +240,18 @@ class TestAutomationNameUniqueness:
|
||||
|
||||
class TestAutomationPersistence:
|
||||
def test_persist_and_reload(self, tmp_path):
|
||||
path = str(tmp_path / "auto_persist.json")
|
||||
s1 = AutomationStore(path)
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "auto_persist.db")
|
||||
s1 = AutomationStore(db)
|
||||
a = s1.create_automation(
|
||||
name="Persist",
|
||||
conditions=[WebhookCondition(token="t1")],
|
||||
)
|
||||
aid = a.id
|
||||
|
||||
s2 = AutomationStore(path)
|
||||
s2 = AutomationStore(db)
|
||||
loaded = s2.get_automation(aid)
|
||||
assert loaded.name == "Persist"
|
||||
assert len(loaded.conditions) == 1
|
||||
assert isinstance(loaded.conditions[0], WebhookCondition)
|
||||
db.close()
|
||||
|
||||
@@ -14,13 +14,16 @@ from wled_controller.storage.device_store import Device, DeviceStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_storage(tmp_path) -> Path:
|
||||
return tmp_path / "devices.json"
|
||||
def tmp_db(tmp_path):
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "test.db")
|
||||
yield db
|
||||
db.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store(temp_storage) -> DeviceStore:
|
||||
return DeviceStore(temp_storage)
|
||||
def store(tmp_db) -> DeviceStore:
|
||||
return DeviceStore(tmp_db)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -240,23 +243,29 @@ class TestDeviceNameUniqueness:
|
||||
|
||||
|
||||
class TestDevicePersistence:
|
||||
def test_persistence_across_instances(self, temp_storage):
|
||||
s1 = DeviceStore(temp_storage)
|
||||
def test_persistence_across_instances(self, tmp_path):
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "persist.db")
|
||||
s1 = DeviceStore(db)
|
||||
d = s1.create_device(name="Persist", url="http://p", led_count=77)
|
||||
did = d.id
|
||||
|
||||
s2 = DeviceStore(temp_storage)
|
||||
s2 = DeviceStore(db)
|
||||
loaded = s2.get_device(did)
|
||||
assert loaded.name == "Persist"
|
||||
assert loaded.led_count == 77
|
||||
db.close()
|
||||
|
||||
def test_update_persists(self, temp_storage):
|
||||
s1 = DeviceStore(temp_storage)
|
||||
def test_update_persists(self, tmp_path):
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "persist2.db")
|
||||
s1 = DeviceStore(db)
|
||||
d = s1.create_device(name="Before", url="http://x", led_count=10)
|
||||
s1.update_device(d.id, name="After")
|
||||
|
||||
s2 = DeviceStore(temp_storage)
|
||||
s2 = DeviceStore(db)
|
||||
assert s2.get_device(d.id).name == "After"
|
||||
db.close()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -266,7 +275,9 @@ class TestDevicePersistence:
|
||||
|
||||
class TestDeviceThreadSafety:
|
||||
def test_concurrent_creates(self, tmp_path):
|
||||
s = DeviceStore(tmp_path / "conc.json")
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "conc.db")
|
||||
s = DeviceStore(db)
|
||||
errors = []
|
||||
|
||||
def _create(i):
|
||||
|
||||
@@ -11,8 +11,8 @@ from wled_controller.storage.key_colors_output_target import (
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store(tmp_path) -> OutputTargetStore:
|
||||
return OutputTargetStore(str(tmp_path / "output_targets.json"))
|
||||
def store(tmp_db) -> OutputTargetStore:
|
||||
return OutputTargetStore(tmp_db)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -193,8 +193,10 @@ class TestOutputTargetQueries:
|
||||
|
||||
class TestOutputTargetPersistence:
|
||||
def test_persist_and_reload(self, tmp_path):
|
||||
path = str(tmp_path / "ot_persist.json")
|
||||
s1 = OutputTargetStore(path)
|
||||
from wled_controller.storage.database import Database
|
||||
db_path = str(tmp_path / "ot_persist.db")
|
||||
db = Database(db_path)
|
||||
s1 = OutputTargetStore(db)
|
||||
t = s1.create_target(
|
||||
"Persist", "led",
|
||||
device_id="dev_1",
|
||||
@@ -203,8 +205,9 @@ class TestOutputTargetPersistence:
|
||||
)
|
||||
tid = t.id
|
||||
|
||||
s2 = OutputTargetStore(path)
|
||||
s2 = OutputTargetStore(db)
|
||||
loaded = s2.get_target(tid)
|
||||
assert loaded.name == "Persist"
|
||||
assert isinstance(loaded, WledOutputTarget)
|
||||
assert loaded.tags == ["tv"]
|
||||
db.close()
|
||||
|
||||
@@ -7,8 +7,8 @@ from wled_controller.storage.sync_clock_store import SyncClockStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store(tmp_path) -> SyncClockStore:
|
||||
return SyncClockStore(str(tmp_path / "sync_clocks.json"))
|
||||
def store(tmp_db) -> SyncClockStore:
|
||||
return SyncClockStore(tmp_db)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -149,12 +149,14 @@ class TestSyncClockNameUniqueness:
|
||||
|
||||
class TestSyncClockPersistence:
|
||||
def test_persist_and_reload(self, tmp_path):
|
||||
path = str(tmp_path / "sc_persist.json")
|
||||
s1 = SyncClockStore(path)
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "sc_persist.db")
|
||||
s1 = SyncClockStore(db)
|
||||
c = s1.create_clock(name="Persist", speed=2.5)
|
||||
cid = c.id
|
||||
|
||||
s2 = SyncClockStore(path)
|
||||
s2 = SyncClockStore(db)
|
||||
loaded = s2.get_clock(cid)
|
||||
assert loaded.name == "Persist"
|
||||
assert loaded.speed == 2.5
|
||||
db.close()
|
||||
|
||||
@@ -14,8 +14,8 @@ from wled_controller.storage.value_source_store import ValueSourceStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store(tmp_path) -> ValueSourceStore:
|
||||
return ValueSourceStore(str(tmp_path / "value_sources.json"))
|
||||
def store(tmp_db) -> ValueSourceStore:
|
||||
return ValueSourceStore(tmp_db)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -247,13 +247,15 @@ class TestValueSourceNameUniqueness:
|
||||
|
||||
class TestValueSourcePersistence:
|
||||
def test_persist_and_reload(self, tmp_path):
|
||||
path = str(tmp_path / "vs_persist.json")
|
||||
s1 = ValueSourceStore(path)
|
||||
from wled_controller.storage.database import Database
|
||||
db = Database(tmp_path / "vs_persist.db")
|
||||
s1 = ValueSourceStore(db)
|
||||
src = s1.create_source("Persist", "static", value=0.42)
|
||||
sid = src.id
|
||||
|
||||
s2 = ValueSourceStore(path)
|
||||
s2 = ValueSourceStore(db)
|
||||
loaded = s2.get_source(sid)
|
||||
assert loaded.name == "Persist"
|
||||
assert isinstance(loaded, StaticValueSource)
|
||||
assert loaded.value == 0.42
|
||||
db.close()
|
||||
|
||||
@@ -21,8 +21,7 @@ class TestDefaultConfig:
|
||||
|
||||
def test_default_storage_paths(self):
|
||||
config = Config()
|
||||
assert config.storage.devices_file == "data/devices.json"
|
||||
assert config.storage.sync_clocks_file == "data/sync_clocks.json"
|
||||
assert config.storage.database_file == "data/ledgrab.db"
|
||||
|
||||
def test_default_mqtt_disabled(self):
|
||||
config = Config()
|
||||
@@ -73,12 +72,11 @@ class TestServerConfig:
|
||||
class TestDemoMode:
|
||||
def test_demo_rewrites_storage_paths(self):
|
||||
config = Config(demo=True)
|
||||
assert config.storage.devices_file.startswith("data/demo/")
|
||||
assert config.storage.sync_clocks_file.startswith("data/demo/")
|
||||
assert config.storage.database_file.startswith("data/demo/")
|
||||
|
||||
def test_non_demo_keeps_original_paths(self):
|
||||
config = Config(demo=False)
|
||||
assert config.storage.devices_file == "data/devices.json"
|
||||
assert config.storage.database_file == "data/ledgrab.db"
|
||||
|
||||
|
||||
class TestGlobalConfig:
|
||||
|
||||
@@ -2,19 +2,22 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from wled_controller.storage.database import Database
|
||||
from wled_controller.storage.device_store import Device, DeviceStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_storage(tmp_path):
|
||||
"""Provide temporary storage file."""
|
||||
return tmp_path / "devices.json"
|
||||
def tmp_db(tmp_path):
|
||||
"""Provide a temporary SQLite Database instance."""
|
||||
db = Database(tmp_path / "test.db")
|
||||
yield db
|
||||
db.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_store(temp_storage):
|
||||
def device_store(tmp_db):
|
||||
"""Provide device store instance."""
|
||||
return DeviceStore(temp_storage)
|
||||
return DeviceStore(tmp_db)
|
||||
|
||||
|
||||
def test_device_creation():
|
||||
@@ -207,10 +210,11 @@ def test_device_exists(device_store):
|
||||
assert device_store.device_exists("nonexistent") is False
|
||||
|
||||
|
||||
def test_persistence(temp_storage):
|
||||
def test_persistence(tmp_path):
|
||||
"""Test device persistence across store instances."""
|
||||
db = Database(tmp_path / "persist.db")
|
||||
# Create store and add device
|
||||
store1 = DeviceStore(temp_storage)
|
||||
store1 = DeviceStore(db)
|
||||
device = store1.create_device(
|
||||
name="Test WLED",
|
||||
url="http://192.168.1.100",
|
||||
@@ -218,14 +222,15 @@ def test_persistence(temp_storage):
|
||||
)
|
||||
device_id = device.id
|
||||
|
||||
# Create new store instance (loads from file)
|
||||
store2 = DeviceStore(temp_storage)
|
||||
# Create new store instance (loads from database)
|
||||
store2 = DeviceStore(db)
|
||||
|
||||
# Verify device persisted
|
||||
loaded_device = store2.get_device(device_id)
|
||||
assert loaded_device is not None
|
||||
assert loaded_device.name == "Test WLED"
|
||||
assert loaded_device.led_count == 150
|
||||
db.close()
|
||||
|
||||
|
||||
def test_clear(device_store):
|
||||
|
||||
Reference in New Issue
Block a user