57663400ce
- Add GET /api/v1/models/{model_name}/show endpoint (proxy to Ollama /api/show)
- Worker now fetches show data for each model during model list sync
- Persist show details in localStorage under llm_monitor_models.showByModel
- Make model cards clickable to display cached show details in a dedicated panel
- Keep UI updates incremental without full page reload
- Add tests for show endpoint and OpenAPI path
- Update README and PRD with show-flow and click-card behavior
140 lines
4.8 KiB
Python
140 lines
4.8 KiB
Python
"""
|
|
Test API endpoints
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
def test_health_check(client):
|
|
"""Test health endpoint"""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_get.return_value = mock_response
|
|
|
|
response = client.get("/api/v1/health")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "status" in data
|
|
assert data["status"] == "healthy"
|
|
|
|
def test_ready_endpoint(client):
|
|
"""Test readiness probe"""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_get.return_value = mock_response
|
|
|
|
response = client.get("/api/v1/ready")
|
|
assert response.status_code == 200
|
|
assert response.json() == {"status": "ready"}
|
|
|
|
def test_get_models(client, mock_models_response):
|
|
"""Test getting models list"""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = mock_models_response
|
|
mock_get.return_value = mock_response
|
|
|
|
response = client.get("/api/v1/models")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "models" in data
|
|
assert "total" in data
|
|
assert data["total"] == 2
|
|
assert len(data["models"]) == 2
|
|
assert data["models"][0]["name"] == "llama2"
|
|
|
|
def test_get_models_ollama_offline(client):
|
|
"""Test getting models when Ollama is offline"""
|
|
with patch("requests.get") as mock_get:
|
|
mock_get.side_effect = Exception("Connection refused")
|
|
|
|
response = client.get("/api/v1/models")
|
|
assert response.status_code == 500
|
|
|
|
def test_get_specific_model(client, mock_models_response):
|
|
"""Test getting specific model"""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = mock_models_response
|
|
mock_get.return_value = mock_response
|
|
|
|
response = client.get("/api/v1/models/llama2")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["name"] == "llama2"
|
|
|
|
def test_get_nonexistent_model(client, mock_models_response):
|
|
"""Test getting nonexistent model"""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = mock_models_response
|
|
mock_get.return_value = mock_response
|
|
|
|
response = client.get("/api/v1/models/nonexistent")
|
|
assert response.status_code == 404
|
|
|
|
|
|
def test_get_model_show(client):
|
|
"""Test show endpoint for model details."""
|
|
with patch("requests.post") as mock_post:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
"details": {
|
|
"family": "llama",
|
|
"parameter_size": "8B"
|
|
},
|
|
"model_info": {
|
|
"general.architecture": "llama"
|
|
}
|
|
}
|
|
mock_post.return_value = mock_response
|
|
|
|
response = client.get("/api/v1/models/llama2/show")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "details" in data
|
|
assert data["details"]["family"] == "llama"
|
|
|
|
|
|
def test_get_model_show_not_found(client):
|
|
"""Test show endpoint when model is not found."""
|
|
with patch("requests.post") as mock_post:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 404
|
|
mock_post.return_value = mock_response
|
|
|
|
response = client.get("/api/v1/models/nonexistent/show")
|
|
assert response.status_code == 404
|
|
|
|
def test_root_endpoint(client):
|
|
"""Test root endpoint redirects to dashboard"""
|
|
response = client.get("/", follow_redirects=False)
|
|
assert response.status_code in [200, 307]
|
|
|
|
def test_openapi_schema(client):
|
|
"""Test OpenAPI schema is available"""
|
|
response = client.get("/openapi.json")
|
|
assert response.status_code == 200
|
|
schema = response.json()
|
|
assert "info" in schema
|
|
assert "paths" in schema
|
|
assert "/api/v1/health" in schema["paths"]
|
|
assert "/api/v1/models" in schema["paths"]
|
|
assert "/api/v1/models/{model_name}/show" in schema["paths"]
|
|
assert "/api/v1/models/{model_name}/pull" not in schema["paths"]
|
|
|
|
|
|
def test_write_endpoints_disabled_by_default(client):
|
|
"""POST/DELETE sui modelli devono essere non disponibili di default."""
|
|
response_pull = client.post("/api/v1/models/llama2/pull")
|
|
assert response_pull.status_code == 404
|
|
|
|
response_delete = client.delete("/api/v1/models/llama2")
|
|
assert response_delete.status_code == 404
|