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.
214 lines
7.2 KiB
Python
214 lines
7.2 KiB
Python
"""Tests for OutputTargetStore — CRUD for LED and key_colors targets."""
|
|
|
|
import pytest
|
|
|
|
from wled_controller.storage.output_target import OutputTarget
|
|
from wled_controller.storage.output_target_store import OutputTargetStore
|
|
from wled_controller.storage.wled_output_target import WledOutputTarget
|
|
from wled_controller.storage.key_colors_output_target import (
|
|
KeyColorsOutputTarget,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def store(tmp_db) -> OutputTargetStore:
|
|
return OutputTargetStore(tmp_db)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# OutputTarget model dispatching
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestOutputTargetModel:
|
|
def test_led_from_dict(self):
|
|
data = {
|
|
"id": "pt_1",
|
|
"name": "LED Target",
|
|
"target_type": "led",
|
|
"device_id": "dev_1",
|
|
"color_strip_source_id": "css_1",
|
|
"fps": 30,
|
|
"protocol": "ddp",
|
|
"created_at": "2025-01-01T00:00:00+00:00",
|
|
"updated_at": "2025-01-01T00:00:00+00:00",
|
|
}
|
|
target = OutputTarget.from_dict(data)
|
|
assert isinstance(target, WledOutputTarget)
|
|
assert target.device_id == "dev_1"
|
|
|
|
def test_key_colors_from_dict(self):
|
|
data = {
|
|
"id": "pt_2",
|
|
"name": "KC Target",
|
|
"target_type": "key_colors",
|
|
"picture_source_id": "ps_1",
|
|
"settings": {},
|
|
"created_at": "2025-01-01T00:00:00+00:00",
|
|
"updated_at": "2025-01-01T00:00:00+00:00",
|
|
}
|
|
target = OutputTarget.from_dict(data)
|
|
assert isinstance(target, KeyColorsOutputTarget)
|
|
|
|
def test_unknown_type_raises(self):
|
|
data = {
|
|
"id": "pt_3",
|
|
"name": "Bad",
|
|
"target_type": "nonexistent",
|
|
"created_at": "2025-01-01T00:00:00+00:00",
|
|
"updated_at": "2025-01-01T00:00:00+00:00",
|
|
}
|
|
with pytest.raises(ValueError, match="Unknown target type"):
|
|
OutputTarget.from_dict(data)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# OutputTargetStore CRUD
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestOutputTargetStoreCRUD:
|
|
def test_create_led_target(self, store):
|
|
t = store.create_target(
|
|
name="LED 1",
|
|
target_type="led",
|
|
device_id="dev_1",
|
|
color_strip_source_id="css_1",
|
|
fps=60,
|
|
protocol="ddp",
|
|
)
|
|
assert t.id.startswith("pt_")
|
|
assert isinstance(t, WledOutputTarget)
|
|
assert t.name == "LED 1"
|
|
assert store.count() == 1
|
|
|
|
def test_create_key_colors_target(self, store):
|
|
t = store.create_target(
|
|
name="KC 1",
|
|
target_type="key_colors",
|
|
picture_source_id="ps_1",
|
|
)
|
|
assert isinstance(t, KeyColorsOutputTarget)
|
|
assert t.picture_source_id == "ps_1"
|
|
|
|
def test_create_invalid_type(self, store):
|
|
with pytest.raises(ValueError, match="Invalid target type"):
|
|
store.create_target(name="Bad", target_type="invalid")
|
|
|
|
def test_get_all(self, store):
|
|
store.create_target("A", "led")
|
|
store.create_target("B", "led")
|
|
assert len(store.get_all_targets()) == 2
|
|
|
|
def test_get(self, store):
|
|
created = store.create_target("Get", "led")
|
|
got = store.get_target(created.id)
|
|
assert got.name == "Get"
|
|
|
|
def test_delete(self, store):
|
|
t = store.create_target("Del", "led")
|
|
store.delete_target(t.id)
|
|
assert store.count() == 0
|
|
|
|
def test_delete_not_found(self, store):
|
|
with pytest.raises(ValueError, match="not found"):
|
|
store.delete_target("nope")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Update
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestOutputTargetUpdate:
|
|
def test_update_name(self, store):
|
|
t = store.create_target("Old", "led")
|
|
updated = store.update_target(t.id, name="New")
|
|
assert updated.name == "New"
|
|
|
|
def test_update_led_fields(self, store):
|
|
t = store.create_target("LED", "led", fps=30, protocol="ddp")
|
|
updated = store.update_target(t.id, fps=60, protocol="drgb")
|
|
assert isinstance(updated, WledOutputTarget)
|
|
assert updated.fps == 60
|
|
assert updated.protocol == "drgb"
|
|
|
|
def test_update_not_found(self, store):
|
|
with pytest.raises(ValueError, match="not found"):
|
|
store.update_target("nope", name="X")
|
|
|
|
def test_update_tags(self, store):
|
|
t = store.create_target("Tags", "led", tags=["old"])
|
|
updated = store.update_target(t.id, tags=["new", "tags"])
|
|
assert updated.tags == ["new", "tags"]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Name uniqueness
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestOutputTargetNameUniqueness:
|
|
def test_duplicate_name_create(self, store):
|
|
store.create_target("Same", "led")
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
store.create_target("Same", "led")
|
|
|
|
def test_duplicate_name_update(self, store):
|
|
store.create_target("First", "led")
|
|
t2 = store.create_target("Second", "led")
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
store.update_target(t2.id, name="First")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Query helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestOutputTargetQueries:
|
|
def test_get_targets_for_device(self, store):
|
|
store.create_target("T1", "led", device_id="dev_a")
|
|
store.create_target("T2", "led", device_id="dev_b")
|
|
store.create_target("T3", "led", device_id="dev_a")
|
|
|
|
results = store.get_targets_for_device("dev_a")
|
|
assert len(results) == 2
|
|
assert all(isinstance(t, WledOutputTarget) for t in results)
|
|
|
|
def test_get_targets_for_device_empty(self, store):
|
|
assert store.get_targets_for_device("nonexistent") == []
|
|
|
|
def test_get_targets_referencing_css(self, store):
|
|
store.create_target("T1", "led", color_strip_source_id="css_x")
|
|
store.create_target("T2", "led", color_strip_source_id="css_y")
|
|
names = store.get_targets_referencing_css("css_x")
|
|
assert names == ["T1"]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Persistence
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestOutputTargetPersistence:
|
|
def test_persist_and_reload(self, tmp_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",
|
|
fps=60,
|
|
tags=["tv"],
|
|
)
|
|
tid = t.id
|
|
|
|
s2 = OutputTargetStore(db)
|
|
loaded = s2.get_target(tid)
|
|
assert loaded.name == "Persist"
|
|
assert isinstance(loaded, WledOutputTarget)
|
|
assert loaded.tags == ["tv"]
|
|
db.close()
|