Spaces:
Running
Running
| """ | |
| Route-level tests for /api/hf/monitoring endpoint. | |
| Updated for DeepSeek AI monitoring. | |
| """ | |
| import os | |
| from unittest.mock import MagicMock, Mock, patch | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| import main as main_module | |
| from main import app | |
| main_module._firebase_ready = True | |
| main_module._init_firebase_admin = lambda: None | |
| main_module.firebase_firestore = None | |
| if getattr(main_module, "firebase_auth", None) is None: | |
| main_module.firebase_auth = MagicMock() | |
| main_module.firebase_auth.verify_id_token = MagicMock(return_value={ | |
| "uid": "test-teacher-uid", | |
| "email": "teacher@example.com", | |
| "role": "teacher", | |
| }) | |
| admin_client = TestClient(app, headers={"Authorization": "Bearer admin-token"}) | |
| EXPECTED_MONITORING_FIELDS = { | |
| "modelId", "modelStatus", "avgResponseTimeMs", | |
| "embeddingModelId", "embeddingModelStatus", | |
| "inferenceBalance", "totalPeriodCost", | |
| "hubApiCallsUsed", "hubApiCallsLimit", | |
| "zeroGpuMinutesUsed", "zeroGpuMinutesLimit", | |
| "publicStorageUsedTB", "publicStorageLimitTB", | |
| "lastChecked", "periodStart", "periodEnd", | |
| "activeProfile", "runtimeOverridesActive", "resolvedModels", | |
| "provider", "apiBaseUrl", | |
| } | |
| EXPECTED_FIELDS_AFTER_DS_REPLACEMENT = EXPECTED_MONITORING_FIELDS | |
| def _mock_env(): | |
| with patch.dict(os.environ, {"DEEPSEEK_API_KEY": "test-ds-monitoring-key"}): | |
| yield | |
| # โโโ Auth Enforcement โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| class TestMonitoringAuth: | |
| def test_rejects_bad_token(self): | |
| main_module.firebase_auth.verify_id_token = MagicMock(side_effect=Exception("bad")) | |
| c = TestClient(app, headers={"Authorization": "Bearer bad-token"}) | |
| response = c.get("/api/hf/monitoring") | |
| main_module.firebase_auth.verify_id_token = MagicMock(return_value={ | |
| "uid": "admin-uid", "email": "admin@example.com", "role": "admin", | |
| }) | |
| assert response.status_code in {401, 403} | |
| # โโโ Response Shape โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| class TestMonitoringResponseShape: | |
| def test_success_response_contains_all_expected_fields(self, mock_time): | |
| mock_time.return_value = 1000.0 | |
| response = admin_client.get("/api/hf/monitoring") | |
| assert response.status_code == 200 | |
| data = response.json() | |
| assert data["success"] is True | |
| payload = data["data"] | |
| for field in EXPECTED_FIELDS_AFTER_DS_REPLACEMENT: | |
| assert field in payload, f"Missing field: {field}" | |
| def test_all_probes_fail_gracefully(self, mock_ds_client_fn, mock_time): | |
| mock_time.return_value = 1000.0 | |
| mock_client = MagicMock() | |
| mock_client.chat.completions.create.side_effect = Exception("network down") | |
| mock_ds_client_fn.return_value = mock_client | |
| response = admin_client.get("/api/hf/monitoring") | |
| assert response.status_code == 200 | |
| data = response.json() | |
| assert data["success"] is True | |
| # โโโ Response Values โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| class TestMonitoringResponseValues: | |
| def test_model_status_is_degraded_when_probe_fails(self, mock_time, mock_ds_client_fn): | |
| mock_time.return_value = 1000.0 | |
| mock_client = MagicMock() | |
| mock_client.chat.completions.create.side_effect = Exception("probe down") | |
| mock_ds_client_fn.return_value = mock_client | |
| response = admin_client.get("/api/hf/monitoring") | |
| data = response.json() | |
| assert data["success"] is True | |
| assert data["data"]["modelStatus"] == "Degraded" | |
| def test_embedding_model_id_is_returned(self, mock_time): | |
| mock_time.return_value = 1000.0 | |
| response = admin_client.get("/api/hf/monitoring") | |
| data = response.json() | |
| assert data["success"] is True | |
| assert "bge-small" in data["data"]["embeddingModelId"].lower() | |
| def test_resolved_models_contains_task_keys(self, mock_time): | |
| mock_time.return_value = 1000.0 | |
| response = admin_client.get("/api/hf/monitoring") | |
| data = response.json() | |
| resolved = data["data"].get("resolvedModels", {}) | |
| expected_tasks = {"chat", "rag_lesson", "rag_problem", "quiz_generation"} | |
| for task in expected_tasks: | |
| assert task in resolved, f"Missing task: {task}" | |
| assert isinstance(resolved[task], str) and len(resolved[task]) > 0 | |
| def test_active_profile_returned(self, mock_time): | |
| mock_time.return_value = 1000.0 | |
| response = admin_client.get("/api/hf/monitoring") | |
| data = response.json() | |
| assert data["success"] is True | |
| assert data["data"]["activeProfile"] in {"dev", "budget", "prod", ""} | |
| def test_provider_and_api_base_url_present(self, mock_time): | |
| mock_time.return_value = 1000.0 | |
| response = admin_client.get("/api/hf/monitoring") | |
| data = response.json() | |
| assert data["success"] is True | |
| assert data["data"]["provider"] == "deepseek" | |
| assert "api.deepseek.com" in data["data"]["apiBaseUrl"] | |