Add test suite for Lyria Studio backend

- conftest.py: isolated async test fixtures with temp DB and directories
- test_waveform.py: waveform generation, downsampling, caching, SVG output
- test_api.py: full API endpoint tests (health, models, clips CRUD,
  waveform endpoint, admin cache clearing)
- test_analysis.py: BPM detection, key detection, clip analysis
- test_models.py: request validation, model registry, prompt building

- Fixed off-by-one in waveform.py downsampling (linspace upper bound)
- All 40 tests passing
This commit is contained in:
rin.kagamine committed 2026-05-31 08:26:01 -04:00
1 parent 3500c73167
commit 6c1e1b4509
7 files changed
+742 -1

No files matched your search

+90
View File
@@ -0,0 +1,90 @@
"""Tests for Pydantic models."""
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
from models import GenerateRequest, GenerateResponse, ClipList, LYRIA_MODELS, DEFAULT_MODEL
class TestGenerateRequest:
"""Request validation and prompt building."""
def test_default_model_and_duration(self):
req = GenerateRequest(prompt="gabber kick")
assert req.model == DEFAULT_MODEL
dur = req.get_effective_duration()
assert dur == 30 # clip preview default
def test_pro_model_with_custom_duration(self):
req = GenerateRequest(prompt="180 BPM hardcore", model="lyria-3-pro-preview", duration=120)
assert req.model == "lyria-3-pro-preview"
dur = req.get_effective_duration()
assert dur == 120
def test_pro_model_duration_clamped_to_max(self):
req = GenerateRequest(prompt="long track", model="lyria-3-pro-preview", duration=999)
dur = req.get_effective_duration()
assert dur == 184 # max for pro model
def test_clip_model_duration_clamped_to_max(self):
req = GenerateRequest(prompt="short clip", model="lyria-3-clip-preview", duration=60)
dur = req.get_effective_duration()
assert dur == 30 # max for clip preview
def test_invalid_model_raises(self):
with pytest.raises(ValueError, match="Unknown model"):
GenerateRequest(prompt="test", model="nonexistent-model")
def test_simple_prompt(self):
req = GenerateRequest(prompt="gabber at 200 BPM")
assert req.build_prompt() == "gabber at 200 BPM"
def test_structured_prompt(self):
req = GenerateRequest(
prompt="ignored",
prompt_structure={
"style": "gabber",
"tempo": "180 BPM",
"mood": "aggressive",
}
)
built = req.build_prompt()
assert "**Style:** gabber" in built
assert "**Tempo:** 180 BPM" in built
assert "**Mood:** aggressive" in built
def test_model_whitespace_trimmed(self):
req = GenerateRequest(prompt="test", model=" lyria-3-clip-preview ")
assert req.model == "lyria-3-clip-preview"
class TestModelConstants:
"""Validate the model registry."""
def test_models_have_required_keys(self):
for model_id, info in LYRIA_MODELS.items():
assert "name" in info, f"{model_id} missing 'name'"
assert "max_duration" in info, f"{model_id} missing 'max_duration'"
assert "default_duration" in info, f"{model_id} missing 'default_duration'"
assert "description" in info, f"{model_id} missing 'description'"
def test_default_model_exists_in_registry(self):
assert DEFAULT_MODEL in LYRIA_MODELS
def test_max_duration_greater_than_default(self):
for model_id, info in LYRIA_MODELS.items():
assert info["max_duration"] >= info["default_duration"], \
f"{model_id}: max_duration < default_duration"
class TestGenerateResponse:
"""Response model."""
def test_create_response(self):
resp = GenerateResponse(id="test-123", status="generating", message="Clip generation started.")
assert resp.id == "test-123"
assert resp.status == "generating"