539 lines
23 KiB
Python
539 lines
23 KiB
Python
# #region Test.Api.DashboardDetailRoutes [C:3] [TYPE Module] [SEMANTICS test,dashboard,detail,api]
|
|
# @BRIEF Unit tests for dashboard detail routes — db-mappings, detail, tasks history, thumbnail.
|
|
# @RELATION BINDS_TO -> [DashboardDetailRoutes]
|
|
# @TEST_EDGE: source_env_not_found -> 404
|
|
# @TEST_EDGE: target_env_not_found -> 404
|
|
# @TEST_EDGE: db_mapping_fail -> 503
|
|
# @TEST_EDGE: dashboard_not_found -> 503
|
|
# @TEST_EDGE: env_not_found_detail -> 404
|
|
|
|
import os
|
|
|
|
os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:")
|
|
os.environ.setdefault("AUTH_DATABASE_URL", "sqlite:///:memory:")
|
|
os.environ.setdefault("SECRET_KEY", "test-secret-key-for-tests")
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
from fastapi import FastAPI
|
|
from fastapi.testclient import TestClient
|
|
|
|
_src = str(Path(__file__).resolve().parent.parent.parent / "src")
|
|
if _src not in sys.path:
|
|
sys.path.insert(0, _src)
|
|
|
|
|
|
def _make_mock_env(id: str = "env-1", name: str = "TestEnv"):
|
|
env = MagicMock()
|
|
env.id = id
|
|
env.name = name
|
|
env.url = "https://superset.example.com"
|
|
env.username = "admin"
|
|
env.password = "pass"
|
|
env.verify_ssl = True
|
|
return env
|
|
|
|
|
|
def _make_client(overrides: dict | None = None) -> TestClient:
|
|
from src.api.routes.dashboards._detail_routes import router
|
|
from src.dependencies import get_config_manager, get_current_user, get_mapping_service, get_task_manager, has_permission
|
|
from src.schemas.auth import User, RoleSchema
|
|
|
|
app = FastAPI()
|
|
app.include_router(router)
|
|
|
|
mock_user = User(
|
|
id="admin-1", username="admin", email="admin@x.com",
|
|
auth_source="LOCAL",
|
|
created_at=__import__("datetime").datetime.now(),
|
|
roles=[RoleSchema(id="r1", name="Admin", description="", permissions=[])],
|
|
)
|
|
|
|
defaults = {
|
|
get_config_manager: lambda: MagicMock(),
|
|
get_mapping_service: lambda: MagicMock(),
|
|
get_task_manager: lambda: MagicMock(),
|
|
get_current_user: lambda: mock_user,
|
|
}
|
|
if overrides:
|
|
defaults.update(overrides)
|
|
for dep, mock_fn in defaults.items():
|
|
app.dependency_overrides[dep] = mock_fn
|
|
return TestClient(app)
|
|
|
|
|
|
# ── get_database_mappings ──
|
|
|
|
class TestGetDatabaseMappings:
|
|
"""GET /api/dashboards/db-mappings"""
|
|
|
|
def test_mappings_success(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [
|
|
_make_mock_env(id="src-env"),
|
|
_make_mock_env(id="tgt-env"),
|
|
]
|
|
mock_mapping = AsyncMock()
|
|
mock_mapping.get_suggestions.return_value = [
|
|
{"source_db": "db1", "target_db": "db2", "source_db_uuid": "u1", "target_db_uuid": "u2", "confidence": 0.95},
|
|
]
|
|
|
|
from src.dependencies import get_config_manager, get_mapping_service
|
|
client = _make_client({
|
|
get_config_manager: lambda: mock_config,
|
|
get_mapping_service: lambda: mock_mapping,
|
|
})
|
|
resp = client.get("/api/dashboards/db-mappings?source_env_id=src-env&target_env_id=tgt-env")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert len(data["mappings"]) == 1
|
|
assert data["mappings"][0]["source_db"] == "db1"
|
|
|
|
def test_mappings_source_not_found(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="tgt-env")]
|
|
|
|
from src.dependencies import get_config_manager
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/db-mappings?source_env_id=src-ghost&target_env_id=tgt-env")
|
|
assert resp.status_code == 404
|
|
assert "Source environment not found" in resp.text
|
|
|
|
def test_mappings_target_not_found(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="src-env")]
|
|
|
|
from src.dependencies import get_config_manager
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/db-mappings?source_env_id=src-env&target_env_id=tgt-ghost")
|
|
assert resp.status_code == 404
|
|
assert "Target environment not found" in resp.text
|
|
|
|
def test_mappings_service_fail(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [
|
|
_make_mock_env(id="src-env"),
|
|
_make_mock_env(id="tgt-env"),
|
|
]
|
|
mock_mapping = AsyncMock()
|
|
mock_mapping.get_suggestions.side_effect = Exception("Service unavailable")
|
|
|
|
from src.dependencies import get_config_manager, get_mapping_service
|
|
client = _make_client({
|
|
get_config_manager: lambda: mock_config,
|
|
get_mapping_service: lambda: mock_mapping,
|
|
})
|
|
resp = client.get("/api/dashboards/db-mappings?source_env_id=src-env&target_env_id=tgt-env")
|
|
assert resp.status_code == 503
|
|
assert "Failed to get database mappings" in resp.text
|
|
|
|
|
|
# ── get_dashboard_detail ──
|
|
|
|
class TestGetDashboardDetail:
|
|
"""GET /api/dashboards/{dashboard_ref}"""
|
|
|
|
def test_detail_success(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
mock_client.get_dashboard_detail.return_value = {
|
|
"id": 42,
|
|
"title": "Test Dash",
|
|
"chart_count": 5,
|
|
"dataset_count": 3,
|
|
"charts": [{"id": 1, "title": "Chart 1", "viz_type": "line"}],
|
|
"datasets": [{"id": 1, "table_name": "sales", "database": "prod"}],
|
|
}
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client") as mock_reg:
|
|
mock_reg.return_value = AsyncMock()
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42?env_id=env-1")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["id"] == 42
|
|
|
|
def test_detail_env_not_found(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = []
|
|
|
|
from src.dependencies import get_config_manager
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42?env_id=env-ghost")
|
|
assert resp.status_code == 404
|
|
assert "Environment not found" in resp.text
|
|
|
|
def test_detail_service_error_503(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboard_detail.side_effect = Exception("Superset API error")
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client") as mock_reg:
|
|
mock_reg.return_value = AsyncMock()
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42?env_id=env-1")
|
|
assert resp.status_code == 503
|
|
assert "Failed to fetch dashboard detail" in resp.text
|
|
|
|
|
|
# ── get_dashboard_tasks_history ──
|
|
|
|
class TestGetDashboardTasksHistory:
|
|
"""GET /api/dashboards/{dashboard_ref}/tasks"""
|
|
|
|
def test_tasks_history_success(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_task = MagicMock()
|
|
mock_task.id = "task-1"
|
|
mock_task.plugin_id = "superset-backup"
|
|
mock_task.status = "SUCCESS"
|
|
mock_task.params = {"dashboards": ["42"], "environment_id": "env-1"}
|
|
mock_task.result = {"status": "ok", "summary": "Backup done"}
|
|
mock_task.started_at = __import__("datetime").datetime(2024, 1, 1)
|
|
mock_task.finished_at = __import__("datetime").datetime(2024, 1, 1, 0, 1)
|
|
|
|
mock_task_manager = MagicMock()
|
|
mock_task_manager.get_all_tasks.return_value = [mock_task]
|
|
|
|
from src.dependencies import get_config_manager, get_task_manager
|
|
client = _make_client({
|
|
get_config_manager: lambda: mock_config,
|
|
get_task_manager: lambda: mock_task_manager,
|
|
})
|
|
resp = client.get("/api/dashboards/42/tasks?env_id=env-1")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["dashboard_id"] == 42
|
|
assert len(data["items"]) == 1
|
|
assert data["items"][0]["id"] == "task-1"
|
|
|
|
def test_tasks_history_empty(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_task_manager = MagicMock()
|
|
mock_task_manager.get_all_tasks.return_value = []
|
|
|
|
from src.dependencies import get_config_manager, get_task_manager
|
|
client = _make_client({
|
|
get_config_manager: lambda: mock_config,
|
|
get_task_manager: lambda: mock_task_manager,
|
|
})
|
|
resp = client.get("/api/dashboards/42/tasks?env_id=env-1")
|
|
assert resp.status_code == 200
|
|
assert resp.json()["items"] == []
|
|
|
|
def test_tasks_history_slug_no_env_id(self):
|
|
mock_task_manager = MagicMock()
|
|
|
|
from src.dependencies import get_config_manager, get_task_manager
|
|
client = _make_client({
|
|
get_config_manager: lambda: MagicMock(),
|
|
get_task_manager: lambda: mock_task_manager,
|
|
})
|
|
resp = client.get("/api/dashboards/slug-ref/tasks")
|
|
assert resp.status_code == 400
|
|
assert "env_id is required" in resp.text
|
|
|
|
def test_tasks_history_env_not_found(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = []
|
|
|
|
from src.dependencies import get_config_manager, get_task_manager
|
|
client = _make_client({
|
|
get_config_manager: lambda: mock_config,
|
|
get_task_manager: lambda: MagicMock(),
|
|
})
|
|
resp = client.get("/api/dashboards/slug-ref/tasks?env_id=env-ghost")
|
|
assert resp.status_code == 404
|
|
assert "Environment not found" in resp.text
|
|
|
|
|
|
# ── get_dashboard_thumbnail ──
|
|
|
|
class TestGetDashboardThumbnail:
|
|
"""GET /api/dashboards/{dashboard_ref}/thumbnail"""
|
|
|
|
def test_thumbnail_success(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
mock_async_client = AsyncMock()
|
|
|
|
async def _fake_request(method, endpoint, **kwargs):
|
|
if "cache_dashboard_screenshot" in endpoint:
|
|
return {"result": {"image_url": "/api/v1/dashboard/42/thumbnail/digest-1/"}}
|
|
if "raw_response" in kwargs and kwargs["raw_response"]:
|
|
mock_resp = MagicMock()
|
|
mock_resp.status_code = 200
|
|
mock_resp.headers = {"Content-Type": "image/png"}
|
|
mock_resp.content = b"fake-image-bytes"
|
|
return mock_resp
|
|
return {}
|
|
|
|
mock_async_client.request.side_effect = _fake_request
|
|
mock_async_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client", return_value=mock_async_client):
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-1")
|
|
assert resp.status_code == 200
|
|
assert resp.content == b"fake-image-bytes"
|
|
|
|
def test_thumbnail_env_not_found(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = []
|
|
|
|
from src.dependencies import get_config_manager
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-ghost")
|
|
assert resp.status_code == 404
|
|
assert "Environment not found" in resp.text
|
|
|
|
def test_thumbnail_202_accepted(self):
|
|
"""Superset returns 202 when thumbnail is being generated."""
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
mock_async_client = AsyncMock()
|
|
|
|
async def _fake_request_202(method, endpoint, **kwargs):
|
|
if "cache_dashboard_screenshot" in endpoint:
|
|
return {"result": {"image_url": "/api/v1/dashboard/42/thumbnail/digest-1/"}}
|
|
if "raw_response" in kwargs and kwargs["raw_response"]:
|
|
mock_resp = MagicMock()
|
|
mock_resp.status_code = 202
|
|
mock_resp.headers = {"Content-Type": "application/json"}
|
|
mock_resp.json.return_value = {"message": "Thumbnail is being generated"}
|
|
return mock_resp
|
|
return {}
|
|
|
|
mock_async_client.request.side_effect = _fake_request_202
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client", return_value=mock_async_client):
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-1&force=true")
|
|
assert resp.status_code == 202
|
|
|
|
def test_thumbnail_dashboard_not_found_404(self):
|
|
"""DashboardNotFoundError returns 404."""
|
|
from src.core.utils.network import DashboardNotFoundError
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
mock_async_client = AsyncMock()
|
|
mock_async_client.request.side_effect = DashboardNotFoundError("Dashboard not found")
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client", return_value=mock_async_client):
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-1")
|
|
assert resp.status_code == 404
|
|
assert "Dashboard thumbnail not found" in resp.text
|
|
|
|
def test_thumbnail_fallback_to_dashboard_url(self):
|
|
"""Fallback when cache_dashboard_screenshot is unavailable."""
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
mock_async_client = AsyncMock()
|
|
|
|
async def _fake_fallback_request(method, endpoint, **kwargs):
|
|
if "cache_dashboard_screenshot" in endpoint:
|
|
return {} # No image_url in response
|
|
if endpoint == "/dashboard/42":
|
|
return {"result": {"thumbnail_url": "/api/v1/dashboard/42/thumbnail/fallback-digest/"}}
|
|
if "raw_response" in kwargs and kwargs["raw_response"]:
|
|
mock_resp = MagicMock()
|
|
mock_resp.status_code = 200
|
|
mock_resp.headers = {"Content-Type": "image/png"}
|
|
mock_resp.content = b"fallback-image"
|
|
return mock_resp
|
|
return {}
|
|
|
|
mock_async_client.request.side_effect = _fake_fallback_request
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client", return_value=mock_async_client):
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-1")
|
|
assert resp.status_code == 200
|
|
assert resp.content == b"fallback-image"
|
|
|
|
def test_thumbnail_generic_error_503(self):
|
|
"""Generic exception returns 503."""
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
mock_async_client = AsyncMock()
|
|
mock_async_client.request.side_effect = RuntimeError("Unexpected error")
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client", return_value=mock_async_client):
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-1")
|
|
assert resp.status_code == 503
|
|
assert "Failed to fetch dashboard thumbnail" in resp.text
|
|
def test_detail_http_exception_re_raised(self):
|
|
"""HTTPException from client is re-raised (line 158 except HTTPException)."""
|
|
from fastapi import HTTPException as FastAPIHTTPException
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
mock_client.get_dashboard_detail.side_effect = FastAPIHTTPException(status_code=400, detail="Bad request")
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client") as mock_reg:
|
|
mock_reg.return_value = AsyncMock()
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42?env_id=env-1")
|
|
assert resp.status_code == 400
|
|
|
|
|
|
# ── get_dashboard_tasks_history — slug ref path ──
|
|
|
|
class TestGetDashboardTasksHistorySlug:
|
|
"""GET /api/dashboards/{slug}/tasks with env_id — slug path (lines 202-203, 268)."""
|
|
|
|
def test_tasks_history_slug_with_env(self):
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_task = MagicMock()
|
|
mock_task.id = "task-1"
|
|
mock_task.plugin_id = "superset-backup"
|
|
mock_task.status = "SUCCESS"
|
|
mock_task.params = {"dashboard_ids": [42], "environment_id": "env-1"}
|
|
mock_task.result = {"status": "ok", "summary": "Backup done"}
|
|
mock_task.started_at = __import__("datetime").datetime(2024, 1, 1)
|
|
mock_task.finished_at = __import__("datetime").datetime(2024, 1, 1, 0, 1)
|
|
|
|
mock_task_manager = MagicMock()
|
|
mock_task_manager.get_all_tasks.return_value = [mock_task]
|
|
|
|
mock_client = AsyncMock()
|
|
# _resolve_dashboard_id_from_ref_async calls get_dashboards_page
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
from src.dependencies import get_config_manager, get_task_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client):
|
|
client = _make_client({
|
|
get_config_manager: lambda: mock_config,
|
|
get_task_manager: lambda: mock_task_manager,
|
|
})
|
|
resp = client.get("/api/dashboards/my-slug/tasks?env_id=env-1")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["dashboard_id"] == 42
|
|
assert len(data["items"]) == 1
|
|
|
|
|
|
# ── get_dashboard_thumbnail — extra edge cases ──
|
|
|
|
class TestGetDashboardThumbnailExtended:
|
|
"""Additional thumbnail path coverage (lines 388-389, 400)."""
|
|
|
|
def test_thumbnail_202_json_error(self):
|
|
"""202 response where JSON parsing fails returns default message (lines 388-389)."""
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
mock_async_client = AsyncMock()
|
|
|
|
async def _fake_request(method, endpoint, **kwargs):
|
|
if "cache_dashboard_screenshot" in endpoint:
|
|
return {"result": {"image_url": "/api/v1/dashboard/42/thumbnail/digest-1/"}}
|
|
if "raw_response" in kwargs and kwargs["raw_response"]:
|
|
mock_resp = MagicMock()
|
|
mock_resp.status_code = 202
|
|
mock_resp.headers = {"Content-Type": "application/json"}
|
|
mock_resp.json.side_effect = ValueError("Invalid JSON")
|
|
return mock_resp
|
|
return {}
|
|
|
|
mock_async_client.request.side_effect = _fake_request
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client", return_value=mock_async_client):
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-1")
|
|
assert resp.status_code == 202
|
|
assert resp.json() == {"message": "Thumbnail is being generated"}
|
|
|
|
def test_thumbnail_http_exception_re_raised(self):
|
|
"""HTTPException from get_superset_client is re-raised (line 400)."""
|
|
from fastapi import HTTPException as FastAPIHTTPException
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = [_make_mock_env(id="env-1")]
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
mock_gsc = AsyncMock()
|
|
async def _raise_gsc(*a, **kw):
|
|
raise FastAPIHTTPException(status_code=409, detail="Conflict")
|
|
mock_gsc.side_effect = _raise_gsc
|
|
|
|
from src.dependencies import get_config_manager
|
|
|
|
with patch("src.api.routes.dashboards._detail_routes.SupersetClient", return_value=mock_client), \
|
|
patch("src.api.routes.dashboards._detail_routes.get_superset_client", new=mock_gsc):
|
|
client = _make_client({get_config_manager: lambda: mock_config})
|
|
resp = client.get("/api/dashboards/42/thumbnail?env_id=env-1")
|
|
assert resp.status_code == 409
|
|
# #endregion Test.Api.DashboardDetailRoutes
|