- 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
90 lines
3.3 KiB
Python
90 lines
3.3 KiB
Python
"""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" |