test: add unit tests for wizard model-discovery helpers
Cover _fetch_local_models (LM Studio and Ollama parsing, error paths, missing base_url), _fetch_lmstudio_available_models (happy path and errors), and _load_lmstudio_model (success, API failure, exception). All mocked via monkeypatch/MagicMock — no real HTTP calls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
"""Tests for setup wizard personalization helpers."""
|
"""Tests for setup wizard personalization and model-discovery helpers."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -90,3 +92,92 @@ def test_suggest_plugins_multiple_categories(monkeypatch):
|
|||||||
combined = " ".join(str(p) for p in panels)
|
combined = " ".join(str(p) for p in panels)
|
||||||
assert "email" in combined
|
assert "email" in combined
|
||||||
assert "ssh_tool" in combined
|
assert "ssh_tool" in combined
|
||||||
|
|
||||||
|
|
||||||
|
# ── _fetch_local_models ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def test_fetch_local_models_lmstudio_returns_model_ids(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
mock_resp = MagicMock()
|
||||||
|
mock_resp.json.return_value = {"data": [{"id": "gemma-4b"}, {"id": "llama3"}]}
|
||||||
|
mock_resp.raise_for_status = lambda: None
|
||||||
|
monkeypatch.setattr(wiz.httpx, "get", lambda *a, **kw: mock_resp)
|
||||||
|
from pyra.setup.providers import get_provider
|
||||||
|
assert wiz._fetch_local_models(get_provider("lmstudio")) == ["gemma-4b", "llama3"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_local_models_ollama_returns_model_names(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
mock_resp = MagicMock()
|
||||||
|
mock_resp.json.return_value = {"models": [{"name": "llama3:latest"}, {"name": "mistral"}]}
|
||||||
|
mock_resp.raise_for_status = lambda: None
|
||||||
|
monkeypatch.setattr(wiz.httpx, "get", lambda *a, **kw: mock_resp)
|
||||||
|
from pyra.setup.providers import get_provider
|
||||||
|
assert wiz._fetch_local_models(get_provider("ollama")) == ["llama3:latest", "mistral"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_local_models_returns_empty_on_connection_error(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
monkeypatch.setattr(wiz.httpx, "get", MagicMock(side_effect=Exception("conn refused")))
|
||||||
|
from pyra.setup.providers import get_provider
|
||||||
|
assert wiz._fetch_local_models(get_provider("lmstudio")) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_local_models_returns_empty_when_no_base_url():
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
from pyra.setup.providers import Provider
|
||||||
|
provider = Provider(
|
||||||
|
id="test", display_name="Test", requires_key=False,
|
||||||
|
default_model="x", litellm_prefix="openai/", group="Local",
|
||||||
|
)
|
||||||
|
assert wiz._fetch_local_models(provider) == []
|
||||||
|
|
||||||
|
|
||||||
|
# ── _fetch_lmstudio_available_models ──────────────────────────────────────────
|
||||||
|
|
||||||
|
def test_fetch_lmstudio_available_models_returns_ids(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
mock_resp = MagicMock()
|
||||||
|
mock_resp.json.return_value = {"data": [{"id": "model-a"}, {"id": "model-b"}]}
|
||||||
|
mock_resp.raise_for_status = lambda: None
|
||||||
|
monkeypatch.setattr(wiz.httpx, "get", lambda *a, **kw: mock_resp)
|
||||||
|
assert wiz._fetch_lmstudio_available_models() == ["model-a", "model-b"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_lmstudio_available_models_returns_empty_on_error(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
monkeypatch.setattr(wiz.httpx, "get", MagicMock(side_effect=Exception("not found")))
|
||||||
|
assert wiz._fetch_lmstudio_available_models() == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_lmstudio_available_models_empty_data(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
mock_resp = MagicMock()
|
||||||
|
mock_resp.json.return_value = {"data": []}
|
||||||
|
mock_resp.raise_for_status = lambda: None
|
||||||
|
monkeypatch.setattr(wiz.httpx, "get", lambda *a, **kw: mock_resp)
|
||||||
|
assert wiz._fetch_lmstudio_available_models() == []
|
||||||
|
|
||||||
|
|
||||||
|
# ── _load_lmstudio_model ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def test_load_lmstudio_model_returns_true_on_success(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
mock_resp = MagicMock()
|
||||||
|
mock_resp.is_success = True
|
||||||
|
monkeypatch.setattr(wiz.httpx, "post", lambda *a, **kw: mock_resp)
|
||||||
|
assert wiz._load_lmstudio_model("gemma-4b") is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_lmstudio_model_returns_false_on_api_failure(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
mock_resp = MagicMock()
|
||||||
|
mock_resp.is_success = False
|
||||||
|
monkeypatch.setattr(wiz.httpx, "post", lambda *a, **kw: mock_resp)
|
||||||
|
assert wiz._load_lmstudio_model("gemma-4b") is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_lmstudio_model_returns_false_on_exception(monkeypatch):
|
||||||
|
import pyra.setup.wizard as wiz
|
||||||
|
monkeypatch.setattr(wiz.httpx, "post", MagicMock(side_effect=Exception("timeout")))
|
||||||
|
assert wiz._load_lmstudio_model("gemma-4b") is False
|
||||||
|
|||||||
Reference in New Issue
Block a user