Ctrl K
ComunidadGuías…

tests/test_app_initializer_memory_vector_degraded.py

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

Archivo original ↗Preguntar a KiBot
"""Regression: a present-but-unhealthy MemoryVectorStore must survive initialization.

When MemoryVectorStore._initialize() fails (ChromaDB unavailable / embeddings not
installed) it swallows the exception and leaves `.healthy == False` — the object
exists but is unhealthy. app_initializer.initialize_managers() previously reset that
object to ``None`` in the ``else`` branch, so service_health.chromadb_health() saw
``memory_vector is None`` and reported the vector memory as DISABLED ("not
configured") instead of DEGRADED/DOWN ("initialization failed") — losing the
diagnostic distinction the /api/diagnostics/services probe is built to surface.

This test fails before the fix (memory_vector is None) and passes after it.
"""
from unittest.mock import MagicMock

import src.app_initializer as app_init
import src.memory_vector as memory_vector_mod
import src.service_health as sh


class _UnhealthyVectorStore:
    """Stand-in for a MemoryVectorStore whose init failed: present but inert."""
    healthy = False

    def count(self):
        return 0

    def search(self, *a, **k):
        return []


def _neutralize_collaborators(monkeypatch):
    """Stub out everything initialize_managers() builds except the vector store,
    so the test isolates the memory_vector health-handling branch."""
    for name in [
        "MemoryManager", "SkillsManager", "SessionManager", "UploadHandler",
        "PersonalDocsManager", "APIKeyManager", "PresetManager",
        "MemoryProviderRegistry", "NativeMemoryProvider", "ChatProcessor",
        "ResearchHandler", "ChatHandler", "ModelDiscovery",
    ]:
        monkeypatch.setattr(app_init, name, lambda *a, **k: MagicMock())
    monkeypatch.setattr(app_init, "set_session_manager", lambda *a, **k: None)
    monkeypatch.setattr(app_init, "update_search_config", lambda *a, **k: None)
    monkeypatch.setattr(app_init, "create_directories", lambda: None)


def test_failed_memory_vector_init_is_kept_not_discarded(monkeypatch, tmp_path):
    _neutralize_collaborators(monkeypatch)
    # initialize_managers does `from src.memory_vector import MemoryVectorStore`
    # at call time, so patch it on the source module.
    monkeypatch.setattr(
        memory_vector_mod, "MemoryVectorStore",
        lambda *a, **k: _UnhealthyVectorStore(),
    )

    result = app_init.initialize_managers(str(tmp_path), rag_manager=None)

    mv = result["memory_vector"]
    assert mv is not None, "unhealthy MemoryVectorStore was discarded (reported as DISABLED, not DEGRADED/DOWN)"
    assert mv.healthy is False


def test_chromadb_health_reports_down_for_unhealthy_vector_store():
    # Pins the downstream taxonomy the fix feeds: a present-but-unhealthy vector
    # store (rag absent) is DOWN, not DISABLED; with a healthy rag it is DEGRADED;
    # only when both are absent is it DISABLED.
    store = _UnhealthyVectorStore()
    healthy_rag = MagicMock(healthy=True)

    assert sh.chromadb_health(None, None)["status"] == sh.DISABLED
    assert sh.chromadb_health(None, store)["status"] == sh.DOWN
    assert sh.chromadb_health(healthy_rag, store)["status"] == sh.DEGRADED