Ctrl K
ComunidadGuías…

tests/installer/test_ollama_step.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Regression : run_ollama doit installer le client 'ollama' meme en mode
--ollama-host distant. Avant le fix, un retour anticipe sautait cette
installation et 'ollama pull' echouait ensuite avec
FileNotFoundError('ollama') sur une machine sans le binaire local."""
from pathlib import Path
from unittest.mock import patch

from installer.core.events import Output
from installer.core.osdetect import parse_os_release
from installer.core.pipeline import StepContext
from installer.core.state import InstallState
from installer.core.steps import ollama

FEDORA = parse_os_release('ID=fedora\nPRETTY_NAME="Fedora 43"\n')


class _FakeBroker:
    def __init__(self, answer=True):
        self.answer = answer
        self.prompts = []

    def confirm(self, prompt, default=True):
        self.prompts.append(prompt)
        return self.answer


def _ctx(host, broker):
    events = []
    state = InstallState(distro=FEDORA, lyra_dir=Path("/tmp/lyra-test"),
                         ollama_host=host)
    ctx = StepContext(state=state, emit=events.append, broker=broker,
                      mcps=(), step_id="ollama")
    return ctx, events


def test_remote_host_installe_le_client_si_absent():
    broker = _FakeBroker(answer=True)
    ctx, _events = _ctx("192.168.122.1", broker)

    with patch("installer.core.steps.ollama.shutil.which", return_value=None), \
         patch("subprocess.run") as mock_run:
        mock_run.return_value.returncode = 0
        mock_run.return_value.stdout = ""
        mock_run.return_value.stderr = ""
        ollama.run_ollama(ctx)

    assert mock_run.called, "le script d'installation du client aurait du etre lance"
    assert broker.prompts, "une confirmation d'installation aurait du etre demandee"


def test_remote_host_skip_install_si_deja_present():
    broker = _FakeBroker(answer=True)
    ctx, events = _ctx("192.168.122.1", broker)

    with patch("installer.core.steps.ollama.shutil.which",
              return_value="/usr/bin/ollama"), \
         patch("subprocess.run") as mock_run:
        ollama.run_ollama(ctx)

    assert not mock_run.called
    assert not broker.prompts
    outputs = [e.line for e in events if isinstance(e, Output)]
    assert any("Ollama distant" in line for line in outputs)


def test_local_sans_host_installe_et_active_service():
    broker = _FakeBroker(answer=True)
    ctx, _events = _ctx("", broker)

    with patch("installer.core.steps.ollama.shutil.which", return_value=None), \
         patch("subprocess.run") as mock_run, \
         patch("installer.core.steps.ollama.run") as mock_systemctl:
        mock_run.return_value.returncode = 0
        mock_run.return_value.stdout = ""
        mock_run.return_value.stderr = ""
        ollama.run_ollama(ctx)

    assert mock_run.called
    assert mock_systemctl.called


class _Proc:
    def __init__(self, code, out=""):
        self.returncode, self.stdout, self.stderr = code, out, ""


def test_regression_script_officiel_reessaye_apres_echec_ponctuel():
    # 2026-09-26, campagne VM : le script d'ollama.com a teste le .tar.zst, raté
    # ponctuellement, s'est rabattu sur le .tgz qui n'existe plus -> 404 -> INSTALLATION
    # ECHOUEE, alors que le passage precedent avait reussi.
    ctx, events = _ctx("192.168.122.1", _FakeBroker())
    runs = [_Proc(1, "curl: (22) The requested URL returned error: 404"), _Proc(0, "Install complete")]
    with patch("installer.core.steps.ollama.shutil.which", return_value=None), \
         patch("subprocess.run", side_effect=runs) as mock_run, \
         patch("installer.core.steps.ollama.time.sleep") as mock_sleep:
        ollama.run_ollama(ctx)
    assert mock_run.call_count == 2
    mock_sleep.assert_called_once_with(ollama.INSTALL_RETRY_PAUSE_S)
    outputs = [e.line for e in events if isinstance(e, Output)]
    assert any("nouvel essai" in line for line in outputs)


def test_script_officiel_abandonne_apres_trois_echecs():
    ctx, _events = _ctx("192.168.122.1", _FakeBroker())
    with patch("installer.core.steps.ollama.shutil.which", return_value=None), \
         patch("subprocess.run", return_value=_Proc(1, "404")) as mock_run, \
         patch("installer.core.steps.ollama.time.sleep"):
        try:
            ollama.run_ollama(ctx)
        except RuntimeError as e:
            assert "3 essais" in str(e)
        else:
            raise AssertionError("l'echec definitif aurait du lever RuntimeError")
    assert mock_run.call_count == ollama.INSTALL_ATTEMPTS


def test_ollama_host_explicite_remplace_un_export_perime(tmp_path, monkeypatch):
    """Regression : --ollama-host doit l'emporter. Avant le fix, un
    `export OLLAMA_HOST=` deja present dans ~/.bashrc etait conserve, et comme
    OLLAMA_HOST prime sur config.yaml au runtime, l'ancienne valeur gagnait."""
    monkeypatch.setenv("HOME", str(tmp_path))
    bashrc = tmp_path / ".bashrc"
    bashrc.write_text("alias a=b\nexport OLLAMA_HOST=ancien:11434\nalias c=d\n", encoding="utf-8")
    ctx, _events = _ctx("192.168.122.1", _FakeBroker())

    with patch("installer.core.steps.ollama.shutil.which", return_value="/usr/bin/ollama"):
        ollama.run_ollama(ctx)
        ollama.run_ollama(ctx)  # idempotent

    text = bashrc.read_text(encoding="utf-8")
    assert "ancien" not in text
    assert text.count("OLLAMA_HOST=") == 1
    assert "export OLLAMA_HOST=192.168.122.1:11434" in text
    assert "alias a=b" in text and "alias c=d" in text