- pyproject.toml: add [tool.ruff] config suppressing E402/W293 globally, F841/E741/E702 in tests, E741 in scripts - inventory.py: split semicolon import (E702) - recipes.py: fix logger -> log (F821 undefined name) - shopping.py: rename l -> lnk in list comprehension (E741) - format_conversion.py: noqa F841 on CUDA flag (used as future hook) - backfill_keywords.py: rename done -> _done (F841) - ingest_purplecarrot.py: drop == True comparison (E712) - Auto-fix: I001 import sorting, F401 unused imports across all files
125 lines
5.2 KiB
Python
125 lines
5.2 KiB
Python
"""Tests for task-based routing added to get_meal_plan_router()."""
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
|
|
def _make_task_ctx(url: str = "http://node:8080") -> MagicMock:
|
|
"""Mock context manager returned by task_allocate()."""
|
|
alloc = MagicMock()
|
|
alloc.url = url
|
|
alloc.allocation_id = "alloc-task-1"
|
|
alloc.service = "cf-text"
|
|
ctx = MagicMock()
|
|
ctx.__enter__ = MagicMock(return_value=alloc)
|
|
ctx.__exit__ = MagicMock(return_value=False)
|
|
return ctx
|
|
|
|
|
|
def _make_task_ctx_not_registered() -> MagicMock:
|
|
"""Mock context manager that raises TaskNotRegistered on enter."""
|
|
from app.services.task_inference import TaskNotRegistered
|
|
ctx = MagicMock()
|
|
ctx.__enter__ = MagicMock(side_effect=TaskNotRegistered("not registered"))
|
|
ctx.__exit__ = MagicMock(return_value=False)
|
|
return ctx
|
|
|
|
|
|
def _make_direct_alloc_ctx(url: str = "http://node:8080") -> MagicMock:
|
|
"""Mock context manager returned by CFOrchClient.allocate()."""
|
|
alloc = MagicMock()
|
|
alloc.url = url
|
|
ctx = MagicMock()
|
|
ctx.__enter__ = MagicMock(return_value=alloc)
|
|
ctx.__exit__ = MagicMock(return_value=False)
|
|
return ctx
|
|
|
|
|
|
def test_task_path_returns_orch_router_on_success(monkeypatch):
|
|
"""get_meal_plan_router() returns _OrchTextRouter when task allocation succeeds."""
|
|
monkeypatch.setenv("CF_ORCH_URL", "http://coord:7700")
|
|
import unittest.mock as um
|
|
# Patch the name as it exists in llm_router's own namespace (module-level import).
|
|
with um.patch("app.services.meal_plan.llm_router.task_allocate",
|
|
return_value=_make_task_ctx(url="http://node:9001")):
|
|
from app.services.meal_plan.llm_router import _OrchTextRouter, get_meal_plan_router
|
|
router, ctx = get_meal_plan_router()
|
|
|
|
assert isinstance(router, _OrchTextRouter)
|
|
assert router._base_url == "http://node:9001"
|
|
|
|
|
|
def test_task_not_registered_falls_back_to_direct_allocate(monkeypatch):
|
|
"""get_meal_plan_router() falls back to direct cf-text allocation on TaskNotRegistered."""
|
|
monkeypatch.setenv("CF_ORCH_URL", "http://coord:7700")
|
|
direct_ctx = _make_direct_alloc_ctx(url="http://node:9002")
|
|
|
|
import unittest.mock as um
|
|
# Patch task_allocate in llm_router's namespace so TaskNotRegistered is raised.
|
|
with um.patch("app.services.meal_plan.llm_router.task_allocate",
|
|
return_value=_make_task_ctx_not_registered()), \
|
|
um.patch("app.services.meal_plan.llm_router.CFOrchClient") as MockClient:
|
|
MockClient.return_value.allocate.return_value = direct_ctx
|
|
from app.services.meal_plan.llm_router import _OrchTextRouter, get_meal_plan_router
|
|
router, ctx = get_meal_plan_router()
|
|
|
|
assert isinstance(router, _OrchTextRouter)
|
|
assert router._base_url == "http://node:9002"
|
|
|
|
|
|
def test_no_cf_orch_url_returns_llm_router(monkeypatch):
|
|
"""get_meal_plan_router() returns LLMRouter when CF_ORCH_URL is not set."""
|
|
monkeypatch.delenv("CF_ORCH_URL", raising=False)
|
|
|
|
import unittest.mock as um
|
|
mock_lr = MagicMock()
|
|
with um.patch("app.services.meal_plan.llm_router.LLMRouter", return_value=mock_lr):
|
|
from app.services.meal_plan.llm_router import get_meal_plan_router
|
|
router, ctx = get_meal_plan_router()
|
|
|
|
assert router is mock_lr
|
|
|
|
|
|
def test_tier1_general_exception_falls_back_to_direct_allocate(monkeypatch):
|
|
"""get_meal_plan_router() falls back to direct allocation when task_allocate raises RuntimeError."""
|
|
monkeypatch.setenv("CF_ORCH_URL", "http://coord:7700")
|
|
direct_ctx = _make_direct_alloc_ctx(url="http://node:9003")
|
|
|
|
import unittest.mock as um
|
|
failing_ctx = MagicMock()
|
|
failing_ctx.__enter__ = MagicMock(side_effect=RuntimeError("coordinator down"))
|
|
failing_ctx.__exit__ = MagicMock(return_value=False)
|
|
|
|
with um.patch("app.services.meal_plan.llm_router.task_allocate",
|
|
return_value=failing_ctx), \
|
|
um.patch("app.services.meal_plan.llm_router.CFOrchClient") as MockClient:
|
|
MockClient.return_value.allocate.return_value = direct_ctx
|
|
from app.services.meal_plan.llm_router import _OrchTextRouter, get_meal_plan_router
|
|
router, ctx = get_meal_plan_router()
|
|
|
|
assert isinstance(router, _OrchTextRouter)
|
|
assert router._base_url == "http://node:9003"
|
|
|
|
|
|
def test_tier2_none_alloc_releases_ctx_and_falls_through(monkeypatch):
|
|
"""get_meal_plan_router() releases Tier 2 ctx and falls through when alloc is None."""
|
|
monkeypatch.setenv("CF_ORCH_URL", "http://coord:7700")
|
|
|
|
import unittest.mock as um
|
|
|
|
none_alloc_ctx = MagicMock()
|
|
none_alloc_ctx.__enter__ = MagicMock(return_value=None)
|
|
none_alloc_ctx.__exit__ = MagicMock(return_value=False)
|
|
|
|
mock_lr = MagicMock()
|
|
|
|
with um.patch("app.services.meal_plan.llm_router.task_allocate",
|
|
return_value=_make_task_ctx_not_registered()), \
|
|
um.patch("app.services.meal_plan.llm_router.CFOrchClient") as MockClient, \
|
|
um.patch("app.services.meal_plan.llm_router.LLMRouter", return_value=mock_lr):
|
|
MockClient.return_value.allocate.return_value = none_alloc_ctx
|
|
from app.services.meal_plan.llm_router import get_meal_plan_router
|
|
router, ctx = get_meal_plan_router()
|
|
|
|
assert router is mock_lr
|
|
none_alloc_ctx.__exit__.assert_called_once_with(None, None, None)
|