Bug fix: - GemmaLLM.chat(): len(chat_ctx) → len(chat_ctx.items) - GemmaLLM._compact_context(): list(chat_ctx) → list(chat_ctx.items) ChatContext in livekit-agents 1.7 is not iterable or sized directly; it exposes an .items list. The TypeError was silently killing all LLM responses (agent heard user but never spoke back). Test suite (tests/): - test_web_ui.py: static assets, token endpoint, LiveKit WS proxy - test_llm_api.py: completion, tool calling, thinking-disabled latency, streaming - test_mcp_tools.py: weather (Fahrenheit), time, memory, skills — all via docker exec + in-container MCP client - test_agent_integration.py: process alive, worker registered, supervisord, container health, LiveKit API - test_compaction.py: size-triggered compaction, system prompt preservation, short-context no-op - conftest.py: shared fixtures (HTTPS client, token, LLM, docker exec helpers) - Run with: .venv-tests/bin/python -m pytest tests/ -v
70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
"""Integration tests for the running container: processes, health, LiveKit."""
|
|
|
|
import re
|
|
|
|
from conftest import docker_exec
|
|
|
|
|
|
def _proc_cmdlines() -> list[str]:
|
|
"""All process cmdlines in the container (no `ps` available)."""
|
|
proc = docker_exec(
|
|
"sh",
|
|
"-c",
|
|
'for p in /proc/[0-9]*/cmdline; do tr "\\0" " " < "$p" 2>/dev/null; echo; done',
|
|
)
|
|
return [line.strip() for line in proc.stdout.splitlines() if line.strip()]
|
|
|
|
|
|
def test_agent_process_alive():
|
|
cmdlines = _proc_cmdlines()
|
|
assert any("agent.py start" in c for c in cmdlines), (
|
|
"no agent.py process found in container"
|
|
)
|
|
|
|
|
|
def test_agent_registered_with_livekit():
|
|
"""`docker logs` runs on the host (not via docker exec)."""
|
|
import subprocess
|
|
|
|
proc = subprocess.run(
|
|
["docker", "logs", "--tail", "500", "voice"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30,
|
|
)
|
|
assert "registered worker" in proc.stdout or "worker registered" in proc.stdout, (
|
|
"agent never registered a worker with LiveKit"
|
|
)
|
|
|
|
|
|
def test_all_supervisord_processes_up():
|
|
"""The supervisorctl socket is not exposed in this image, so verify each
|
|
supervised program's process directly via /proc."""
|
|
cmdlines = _proc_cmdlines()
|
|
|
|
def has(pattern: str) -> bool:
|
|
return any(re.search(pattern, c) for c in cmdlines)
|
|
|
|
assert has(r"livekit --config"), "livekit server not running"
|
|
assert has(r"agent\.py start"), "voice agent not running"
|
|
assert has(r"nginx.*daemon off"), "nginx (web UI) not running"
|
|
assert has(r"token_server\.py"), "token server not running"
|
|
|
|
|
|
def test_container_healthy():
|
|
import subprocess
|
|
|
|
proc = subprocess.run(
|
|
["docker", "inspect", "--format", "{{.State.Health.Status}}", "voice"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30,
|
|
)
|
|
assert proc.stdout.strip() == "healthy"
|
|
|
|
|
|
def test_livekit_server_responds():
|
|
"""LiveKit HTTP API on :7880 (internal; reached via docker exec curl)."""
|
|
proc = docker_exec("curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "http://localhost:7880/")
|
|
assert proc.stdout.strip() in ("200", "404"), f"unexpected status {proc.stdout.strip()!r}"
|