first stab at adding video
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
"""Phase 7 component test: HTTP endpoints (/api/set-avatar, /api/idle-clip,
|
||||
/api/set-video-mode, /api/reload-loras, WebSocket handshake video_mode msg).
|
||||
|
||||
Uses FastAPI's ``TestClient`` so we don't need a running uvicorn server.
|
||||
Stubs the model manager to avoid loading Wan2.2 — we only care that the
|
||||
HTTP surface is plumbed correctly.
|
||||
|
||||
Run:
|
||||
docker compose exec voice-chat python -m tests.component.test_07_endpoints
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
|
||||
from tests.component._common import get_logger
|
||||
|
||||
log = get_logger("test_07")
|
||||
|
||||
|
||||
def _stub_video_engine():
|
||||
class StubCfg:
|
||||
mode = "reflective"
|
||||
class StubEngine:
|
||||
cfg = StubCfg()
|
||||
avatar_path = None
|
||||
def __init__(self): self.idle = b"FAKE_MP4"
|
||||
def is_ready(self): return bool(self.avatar_path)
|
||||
def get_idle_clip(self): return self.idle
|
||||
def set_avatar(self, path): self.avatar_path = path
|
||||
def load_loras(self, specs): self._last_loras = specs
|
||||
return StubEngine()
|
||||
|
||||
|
||||
def run():
|
||||
from fastapi.testclient import TestClient
|
||||
import server.main as main_mod
|
||||
|
||||
# Inject a stub engine so we never touch Wan2.2.
|
||||
main_mod.model_mgr.video_engine = _stub_video_engine()
|
||||
|
||||
# Bypass the heavy lifespan (model loading) so TestClient starts fast.
|
||||
main_mod.app.router.lifespan_context = None # type: ignore[attr-defined]
|
||||
|
||||
client = TestClient(main_mod.app)
|
||||
|
||||
# --- set-avatar ---
|
||||
log.info("[case 1] POST /api/set-avatar")
|
||||
fake_png = b"\x89PNG\r\n\x1a\n" + b"\x00" * 64 # minimal PNG header
|
||||
resp = client.post(
|
||||
"/api/set-avatar",
|
||||
files={"image": ("avatar.png", io.BytesIO(fake_png), "image/png")},
|
||||
)
|
||||
assert resp.status_code == 200, f"got {resp.status_code}: {resp.text}"
|
||||
data = resp.json()
|
||||
assert data["status"] == "ok"
|
||||
assert data["idle_clip_url"] == "/api/idle-clip"
|
||||
log.info(" PASS: %s", data)
|
||||
|
||||
# --- idle-clip ---
|
||||
log.info("[case 2] GET /api/idle-clip")
|
||||
resp = client.get("/api/idle-clip")
|
||||
assert resp.status_code == 200
|
||||
assert resp.content == b"FAKE_MP4"
|
||||
assert resp.headers["content-type"] == "video/mp4"
|
||||
log.info(" PASS")
|
||||
|
||||
# --- set-video-mode ---
|
||||
log.info("[case 3] POST /api/set-video-mode")
|
||||
for mode in ("off", "library", "reflective"):
|
||||
resp = client.post("/api/set-video-mode", data={"mode": mode})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["mode"] == mode
|
||||
resp = client.post("/api/set-video-mode", data={"mode": "bogus"})
|
||||
assert resp.status_code == 400
|
||||
log.info(" PASS")
|
||||
|
||||
# --- reload-loras ---
|
||||
log.info("[case 4] POST /api/reload-loras")
|
||||
body = {
|
||||
"loras": [
|
||||
{"path": "/cache/loras/a.safetensors", "weight": 0.8,
|
||||
"target": "high_noise", "name": "test-a"},
|
||||
{"path": "/cache/loras/b.safetensors", "weight": 0.4,
|
||||
"target": "low_noise"},
|
||||
]
|
||||
}
|
||||
resp = client.post("/api/reload-loras", json=body)
|
||||
assert resp.status_code == 200, resp.text
|
||||
data = resp.json()
|
||||
assert data["lora_count"] == 2
|
||||
log.info(" PASS: %s", data)
|
||||
|
||||
# --- WebSocket video_mode handshake ---
|
||||
log.info("[case 5] WebSocket /ws/chat → video_mode announcement")
|
||||
with client.websocket_connect("/ws/chat") as websocket:
|
||||
msgs = []
|
||||
for _ in range(5):
|
||||
try:
|
||||
msg = websocket.receive_json()
|
||||
msgs.append(msg)
|
||||
if msg.get("type") == "video_mode":
|
||||
break
|
||||
except Exception:
|
||||
break
|
||||
assert any(m.get("type") == "video_mode" for m in msgs), msgs
|
||||
log.info(" PASS")
|
||||
|
||||
log.info("ALL PASSED")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
Reference in New Issue
Block a user