"""Tests unitaires de core.detection.model_health (détection modèles aveugles).""" from __future__ import annotations from unittest.mock import MagicMock, patch import pytest from core.detection import model_health @pytest.fixture(autouse=True) def _clear_cache(): model_health.reset_cache() yield model_health.reset_cache() def _resp(status=200, capabilities=None): r = MagicMock() r.status_code = status r.json.return_value = {"capabilities": capabilities if capabilities is not None else []} return r def test_vision_model_returns_true(): with patch("core.detection.model_health.requests.post", return_value=_resp(200, ["completion", "vision"])): assert model_health.has_vision_capability("gemma4:26b", "http://x:11434") is True def test_blind_model_returns_false(): with patch("core.detection.model_health.requests.post", return_value=_resp(200, ["tools", "completion"])): assert model_health.has_vision_capability("0000/ui-tars-1.5-7b-q8_0:7b", "http://x:11434") is False def test_http_error_is_fail_open(): with patch("core.detection.model_health.requests.post", return_value=_resp(404)): assert model_health.has_vision_capability("absent:latest", "http://x:11434") is True def test_exception_is_fail_open(): with patch("core.detection.model_health.requests.post", side_effect=ConnectionError("boom")): assert model_health.has_vision_capability("any:latest", "http://x:11434") is True def test_cache_avoids_second_call(): with patch("core.detection.model_health.requests.post", return_value=_resp(200, ["vision"])) as p: model_health.has_vision_capability("m", "http://x:11434") model_health.has_vision_capability("m", "http://x:11434") assert p.call_count == 1 # 2e appel servi par le cache def test_smoke_check_reports_each_model(): def _fake_post(url, json=None, timeout=None): name = (json or {}).get("name", "") caps = ["vision"] if name == "good" else ["completion"] return _resp(200, caps) with patch("core.detection.model_health.requests.post", side_effect=_fake_post): res = model_health.smoke_check_models(["good", "blind"], "http://x:11434") assert res == {"good": True, "blind": False}