intelligence-router/tests/test_sidecar_app.py

108 lines
3.7 KiB
Python
Raw Permalink Normal View History

"""Tests for sidecar HTTP endpoints — Issue #2."""
import pytest
import tempfile
from pathlib import Path
from unittest.mock import patch, mock_open
from fastapi.testclient import TestClient
from sidecar.app import app as sidecar_app
@pytest.fixture(autouse=True)
def reset_sidecar_state():
"""Reset shared sidecar state between tests."""
import sidecar.app
old_active = sidecar.app._active_profile
old_proc = sidecar.app._llama_server_process
sidecar.app._active_profile = None
sidecar.app._llama_server_process = None
yield
sidecar.app._active_profile = old_active
sidecar.app._llama_server_process = old_proc
@pytest.fixture
def tmp_manifest(tmp_path):
"""Create a temporary manifest file for testing."""
manifest_file = tmp_path / "manifest.yaml"
manifest_file.write_text(
"- id: qwen-3-8b\n"
" name: \"Qwen 3 8B\"\n"
" model_path: /home/bigt/AI/llm/qwen/qwen3-8b-q4.gguf\n"
" flags:\n"
" n_ctx: 8192\n"
" n_gpu_layers: 35\n"
"- id: llama-4-maverick\n"
" name: \"Llama 4 Maverick\"\n"
" model_path: /home/bigt/AI/llm/llama4/llama4-maverick-q4.gguf\n"
)
return manifest_file
@pytest.fixture
def client(tmp_manifest):
"""Create a test client with a temporary manifest."""
with patch("sidecar.app.MANIFEST_PATH", str(tmp_manifest)):
yield TestClient(sidecar_app)
class TestModelsAvailable:
"""Tests for GET /models/available."""
def test_returns_profiles_from_manifest(self, client):
response = client.get("/models/available")
assert response.status_code == 200
data = response.json()
assert len(data) == 2
assert data[0]["id"] == "qwen-3-8b"
assert data[0]["name"] == "Qwen 3 8B"
assert data[0]["model_path"] == "/home/bigt/AI/llm/qwen/qwen3-8b-q4.gguf"
assert "flags" in data[0]
def test_empty_manifest_returns_empty_list(self, tmp_path):
manifest_file = tmp_path / "empty.yaml"
manifest_file.write_text("[]\n")
with patch("sidecar.app.MANIFEST_PATH", str(manifest_file)):
client = TestClient(sidecar_app)
response = client.get("/models/available")
assert response.status_code == 200
assert response.json() == []
def test_invalid_yaml_returns_500(self, tmp_path):
manifest_file = tmp_path / "invalid.yaml"
manifest_file.write_text("{{{{bad yaml:::\n")
with patch("sidecar.app.MANIFEST_PATH", str(manifest_file)):
client = TestClient(sidecar_app)
response = client.get("/models/available")
assert response.status_code == 500
body = response.json()
assert "detail" in body
def test_missing_file_returns_500(self):
with patch("sidecar.app.MANIFEST_PATH", "/tmp/does_not_exist_12345.yaml"):
client = TestClient(sidecar_app)
response = client.get("/models/available")
assert response.status_code == 500
body = response.json()
assert "detail" in body
def test_each_profile_has_required_fields(self, client):
response = client.get("/models/available")
profiles = response.json()
for p in profiles:
assert "id" in p
assert "name" in p
assert "model_path" in p
assert "flags" in p
class TestModelsStatus:
"""Tests for GET /models/status."""
def test_returns_inactive_status(self, client):
response = client.get("/models/status")
assert response.status_code == 200
data = response.json()
assert data["active_profile"] is None
assert data["llama_server_running"] is False