- search_dashboards: call /api/dashboards with page_context=other and page_size=100 so the profile 'My Dashboards Only' filter can no longer hide the whole catalog; parse available_total/effective_profile_filter and report hidden-by-filter instead of a false 'no dashboards' answer - prefetch_dashboards: same full-catalog context; fix dead code where data=resp.json() sat after return '' inside the error branch, making every 200 response raise NameError and the prefetch always return '' - llm-status: ?force=1 bypasses the 30s health cache so the 'Retry now' button performs a fresh probe instead of re-reading the stale status; frontend keeps a single retry interval (previously stacked intervals decayed the countdown faster than 1/s and fired duplicate probes) - tests: agent tool/prefetch, backend route bypass + force param, frontend retry/force coverage
100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
# #region Test.Agent.Persistence.PrefetchDashboards [C:3] [TYPE Module] [SEMANTICS test,agent,persistence,prefetch,dashboards]
|
|
# @BRIEF Tests for prefetch_dashboards — full-catalog context injection for the LLM.
|
|
# @RELATION BINDS_TO -> [AgentChat.Persistence]
|
|
# @TEST_EDGE: http_error -> non-200 returns empty string
|
|
# @TEST_EDGE: empty_catalog -> "No dashboards found." text
|
|
# @TEST_EDGE: full_catalog -> lists dashboards and requests page_context=other (profile filter bypass)
|
|
import os
|
|
from pathlib import Path
|
|
import sys
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
sys.path.append(str(Path(__file__).resolve().parent.parent.parent / "src"))
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
os.environ.setdefault("FASTAPI_URL", "http://test-backend:8000")
|
|
os.environ.setdefault("SERVICE_JWT", "test-service-jwt")
|
|
os.environ.setdefault("AUTH_SECRET_KEY", "test-secret-key-for-jwt-testing")
|
|
|
|
|
|
def _mock_response(status_code=200, json_data=None):
|
|
resp = MagicMock(spec=httpx.Response)
|
|
resp.status_code = status_code
|
|
resp.json.return_value = json_data or {}
|
|
return resp
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_prefetch_dashboards_uses_full_catalog_context():
|
|
"""prefetch_dashboards must request page_context=other + page_size=100 so the
|
|
"My Dashboards Only" profile filter cannot hide the whole catalog."""
|
|
from ss_tools.agent.context import set_service_jwt, set_user_jwt
|
|
from ss_tools.agent._persistence import prefetch_dashboards
|
|
|
|
set_user_jwt("jwt")
|
|
set_service_jwt("svc-jwt")
|
|
|
|
payload = {
|
|
"dashboards": [
|
|
{"id": i, "title": f"Dash {i}", "slug": f"dash-{i}", "last_modified": "2026-01-01T00:00:00"}
|
|
for i in range(1, 12)
|
|
],
|
|
"total": 11,
|
|
"available_total": 11,
|
|
"effective_profile_filter": {"applied": False, "username": None},
|
|
}
|
|
mock_resp = _mock_response(200, payload)
|
|
|
|
mock_client = AsyncMock(spec=httpx.AsyncClient)
|
|
mock_client.get = AsyncMock(return_value=mock_resp)
|
|
with patch("ss_tools.agent._persistence.get_shared_http_client", return_value=mock_client):
|
|
result = await prefetch_dashboards("ss-dev")
|
|
|
|
call_kwargs = mock_client.get.call_args
|
|
assert call_kwargs is not None
|
|
_, kwargs = call_kwargs
|
|
params = kwargs.get("params", {})
|
|
assert params.get("page_context") == "other"
|
|
assert params.get("page_size") == 100
|
|
|
|
# The previous dead-code bug made every 200 response raise NameError and return "".
|
|
assert result != ""
|
|
assert "11 total" in result
|
|
assert "Dash 1" in result
|
|
assert "Dash 11" in result
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_prefetch_dashboards_http_error_returns_empty():
|
|
"""Non-200 response must degrade to an empty string, not raise."""
|
|
from ss_tools.agent._persistence import prefetch_dashboards
|
|
|
|
mock_client = AsyncMock(spec=httpx.AsyncClient)
|
|
mock_client.get = AsyncMock(return_value=_mock_response(500, {}))
|
|
with patch("ss_tools.agent._persistence.get_shared_http_client", return_value=mock_client):
|
|
result = await prefetch_dashboards("ss-dev")
|
|
|
|
assert result == ""
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_prefetch_dashboards_empty_catalog():
|
|
"""A genuinely empty catalog returns the explicit no-dashboards marker."""
|
|
from ss_tools.agent._persistence import prefetch_dashboards
|
|
|
|
payload = {
|
|
"dashboards": [],
|
|
"total": 0,
|
|
"available_total": 0,
|
|
"effective_profile_filter": {"applied": False, "username": None},
|
|
}
|
|
mock_client = AsyncMock(spec=httpx.AsyncClient)
|
|
mock_client.get = AsyncMock(return_value=_mock_response(200, payload))
|
|
with patch("ss_tools.agent._persistence.get_shared_http_client", return_value=mock_client):
|
|
result = await prefetch_dashboards("ss-dev")
|
|
|
|
assert result == "No dashboards found."
|
|
# #endregion Test.Agent.Persistence.PrefetchDashboards
|