"""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