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.
163 lines
5.3 KiB
Python
163 lines
5.3 KiB
Python
"""Tests for SyncClockStore — CRUD, speed clamping, name uniqueness."""
|
|
|
|
import pytest
|
|
|
|
from wled_controller.storage.sync_clock import SyncClock
|
|
from wled_controller.storage.sync_clock_store import SyncClockStore
|
|
|
|
|
|
@pytest.fixture
|
|
def store(tmp_db) -> SyncClockStore:
|
|
return SyncClockStore(tmp_db)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SyncClock model
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockModel:
|
|
def test_to_dict_round_trip(self, make_sync_clock):
|
|
clock = make_sync_clock(name="RT", speed=2.5, description="test", tags=["a"])
|
|
data = clock.to_dict()
|
|
restored = SyncClock.from_dict(data)
|
|
assert restored.id == clock.id
|
|
assert restored.name == "RT"
|
|
assert restored.speed == 2.5
|
|
assert restored.description == "test"
|
|
assert restored.tags == ["a"]
|
|
|
|
def test_from_dict_defaults(self):
|
|
data = {
|
|
"id": "sc_1",
|
|
"name": "Default",
|
|
"created_at": "2025-01-01T00:00:00+00:00",
|
|
"updated_at": "2025-01-01T00:00:00+00:00",
|
|
}
|
|
clock = SyncClock.from_dict(data)
|
|
assert clock.speed == 1.0
|
|
assert clock.description is None
|
|
assert clock.tags == []
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SyncClockStore CRUD
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockStoreCRUD:
|
|
def test_create_clock(self, store):
|
|
c = store.create_clock(name="Clock A")
|
|
assert c.id.startswith("sc_")
|
|
assert c.name == "Clock A"
|
|
assert c.speed == 1.0
|
|
assert store.count() == 1
|
|
|
|
def test_create_clock_with_options(self, store):
|
|
c = store.create_clock(
|
|
name="Fast", speed=5.0, description="speedy", tags=["anim"]
|
|
)
|
|
assert c.speed == 5.0
|
|
assert c.description == "speedy"
|
|
assert c.tags == ["anim"]
|
|
|
|
def test_get_clock(self, store):
|
|
created = store.create_clock(name="Get")
|
|
got = store.get_clock(created.id)
|
|
assert got.name == "Get"
|
|
|
|
def test_get_all_clocks(self, store):
|
|
store.create_clock("A")
|
|
store.create_clock("B")
|
|
assert len(store.get_all_clocks()) == 2
|
|
|
|
def test_delete_clock(self, store):
|
|
c = store.create_clock("Del")
|
|
store.delete_clock(c.id)
|
|
assert store.count() == 0
|
|
|
|
def test_delete_not_found(self, store):
|
|
with pytest.raises(ValueError, match="not found"):
|
|
store.delete_clock("nope")
|
|
|
|
def test_update_clock(self, store):
|
|
c = store.create_clock(name="Old", speed=1.0)
|
|
updated = store.update_clock(c.id, name="New", speed=3.0)
|
|
assert updated.name == "New"
|
|
assert updated.speed == 3.0
|
|
|
|
def test_update_clock_partial(self, store):
|
|
c = store.create_clock(name="Keep", speed=2.0, description="orig")
|
|
updated = store.update_clock(c.id, speed=4.0)
|
|
assert updated.name == "Keep"
|
|
assert updated.speed == 4.0
|
|
assert updated.description == "orig"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Speed clamping
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSpeedClamping:
|
|
def test_create_clamps_low(self, store):
|
|
c = store.create_clock(name="Low", speed=0.01)
|
|
assert c.speed == 0.1
|
|
|
|
def test_create_clamps_high(self, store):
|
|
c = store.create_clock(name="High", speed=100.0)
|
|
assert c.speed == 10.0
|
|
|
|
def test_update_clamps_low(self, store):
|
|
c = store.create_clock(name="UL", speed=1.0)
|
|
updated = store.update_clock(c.id, speed=-5.0)
|
|
assert updated.speed == 0.1
|
|
|
|
def test_update_clamps_high(self, store):
|
|
c = store.create_clock(name="UH", speed=1.0)
|
|
updated = store.update_clock(c.id, speed=999.0)
|
|
assert updated.speed == 10.0
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Name uniqueness
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockNameUniqueness:
|
|
def test_duplicate_name_create(self, store):
|
|
store.create_clock("Same")
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
store.create_clock("Same")
|
|
|
|
def test_duplicate_name_update(self, store):
|
|
store.create_clock("First")
|
|
c2 = store.create_clock("Second")
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
store.update_clock(c2.id, name="First")
|
|
|
|
def test_rename_to_own_name_ok(self, store):
|
|
c = store.create_clock("Self")
|
|
updated = store.update_clock(c.id, name="Self", speed=9.0)
|
|
assert updated.speed == 9.0
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Persistence
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockPersistence:
|
|
def test_persist_and_reload(self, tmp_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(db)
|
|
loaded = s2.get_clock(cid)
|
|
assert loaded.name == "Persist"
|
|
assert loaded.speed == 2.5
|
|
db.close()
|