Files
ss-tools/backend/src/services/__tests__/test_resource_service.py
2026-02-23 13:15:48 +03:00

215 lines
7.2 KiB
Python

# [DEF:backend.src.services.__tests__.test_resource_service:Module]
# @TIER: STANDARD
# @SEMANTICS: resource-service, tests, dashboards, datasets, activity
# @PURPOSE: Unit tests for ResourceService
# @LAYER: Service
# @RELATION: TESTS -> backend.src.services.resource_service
# @RELATION: VERIFIES -> ResourceService
# @INVARIANT: Resource summaries preserve task linkage and status projection behavior.
import pytest
from unittest.mock import MagicMock, patch, AsyncMock
from datetime import datetime
# [DEF:test_get_dashboards_with_status:Function]
# @PURPOSE: Validate dashboard enrichment includes git/task status projections.
# @TEST: get_dashboards_with_status returns dashboards with git and task status
# @PRE: SupersetClient returns dashboard list
# @POST: Each dashboard has git_status and last_task fields
@pytest.mark.asyncio
async def test_get_dashboards_with_status():
with patch("src.services.resource_service.SupersetClient") as mock_client, \
patch("src.services.resource_service.GitService"):
from src.services.resource_service import ResourceService
service = ResourceService()
# Mock Superset response
mock_client.return_value.get_dashboards_summary.return_value = [
{"id": 1, "title": "Dashboard 1", "slug": "dash-1"},
{"id": 2, "title": "Dashboard 2", "slug": "dash-2"}
]
# Mock tasks
mock_task = MagicMock()
mock_task.id = "task-123"
mock_task.status = "SUCCESS"
mock_task.params = {"resource_id": "dashboard-1"}
mock_task.created_at = datetime.now()
env = MagicMock()
env.id = "prod"
result = await service.get_dashboards_with_status(env, [mock_task])
assert len(result) == 2
assert result[0]["id"] == 1
assert "git_status" in result[0]
assert "last_task" in result[0]
assert result[0]["last_task"]["task_id"] == "task-123"
# [/DEF:test_get_dashboards_with_status:Function]
# [DEF:test_get_datasets_with_status:Function]
# @TEST: get_datasets_with_status returns datasets with task status
# @PRE: SupersetClient returns dataset list
# @POST: Each dataset has last_task field
@pytest.mark.asyncio
async def test_get_datasets_with_status():
with patch("src.services.resource_service.SupersetClient") as mock_client:
from src.services.resource_service import ResourceService
service = ResourceService()
# Mock Superset response
mock_client.return_value.get_datasets_summary.return_value = [
{"id": 1, "table_name": "users", "schema": "public", "database": "app"},
{"id": 2, "table_name": "orders", "schema": "public", "database": "app"}
]
# Mock tasks
mock_task = MagicMock()
mock_task.id = "task-456"
mock_task.status = "RUNNING"
mock_task.params = {"resource_id": "dataset-1"}
mock_task.created_at = datetime.now()
env = MagicMock()
env.id = "prod"
result = await service.get_datasets_with_status(env, [mock_task])
assert len(result) == 2
assert result[0]["table_name"] == "users"
assert "last_task" in result[0]
assert result[0]["last_task"]["task_id"] == "task-456"
assert result[0]["last_task"]["status"] == "RUNNING"
# [/DEF:test_get_datasets_with_status:Function]
# [DEF:test_get_activity_summary:Function]
# @TEST: get_activity_summary returns active count and recent tasks
# @PRE: tasks list provided
# @POST: Returns dict with active_count and recent_tasks
def test_get_activity_summary():
from src.services.resource_service import ResourceService
service = ResourceService()
# Create mock tasks
task1 = MagicMock()
task1.id = "task-1"
task1.status = "RUNNING"
task1.params = {"resource_name": "Dashboard 1", "resource_type": "dashboard"}
task1.created_at = datetime(2024, 1, 1, 10, 0, 0)
task2 = MagicMock()
task2.id = "task-2"
task2.status = "SUCCESS"
task2.params = {"resource_name": "Dataset 1", "resource_type": "dataset"}
task2.created_at = datetime(2024, 1, 1, 9, 0, 0)
task3 = MagicMock()
task3.id = "task-3"
task3.status = "WAITING_INPUT"
task3.params = {"resource_name": "Dashboard 2", "resource_type": "dashboard"}
task3.created_at = datetime(2024, 1, 1, 8, 0, 0)
result = service.get_activity_summary([task1, task2, task3])
assert result["active_count"] == 2 # RUNNING + WAITING_INPUT
assert len(result["recent_tasks"]) == 3
# [/DEF:test_get_activity_summary:Function]
# [DEF:test_get_git_status_for_dashboard_no_repo:Function]
# @TEST: _get_git_status_for_dashboard returns None when no repo exists
# @PRE: GitService returns None for repo
# @POST: Returns None
def test_get_git_status_for_dashboard_no_repo():
with patch("src.services.resource_service.GitService") as mock_git:
from src.services.resource_service import ResourceService
service = ResourceService()
mock_git.return_value.get_repo.return_value = None
result = service._get_git_status_for_dashboard(123)
assert result is None
# [/DEF:test_get_git_status_for_dashboard_no_repo:Function]
# [DEF:test_get_last_task_for_resource:Function]
# @TEST: _get_last_task_for_resource returns most recent task for resource
# @PRE: tasks list with matching resource_id
# @POST: Returns task summary with task_id and status
def test_get_last_task_for_resource():
from src.services.resource_service import ResourceService
service = ResourceService()
# Create mock tasks
task1 = MagicMock()
task1.id = "task-old"
task1.status = "SUCCESS"
task1.params = {"resource_id": "dashboard-1"}
task1.created_at = datetime(2024, 1, 1, 10, 0, 0)
task2 = MagicMock()
task2.id = "task-new"
task2.status = "RUNNING"
task2.params = {"resource_id": "dashboard-1"}
task2.created_at = datetime(2024, 1, 1, 12, 0, 0)
result = service._get_last_task_for_resource("dashboard-1", [task1, task2])
assert result is not None
assert result["task_id"] == "task-new" # Most recent
assert result["status"] == "RUNNING"
# [/DEF:test_get_last_task_for_resource:Function]
# [DEF:test_extract_resource_name_from_task:Function]
# @TEST: _extract_resource_name_from_task extracts name from params
# @PRE: task has resource_name in params
# @POST: Returns resource name or fallback
def test_extract_resource_name_from_task():
from src.services.resource_service import ResourceService
service = ResourceService()
# Task with resource_name
task = MagicMock()
task.id = "task-123"
task.params = {"resource_name": "My Dashboard"}
result = service._extract_resource_name_from_task(task)
assert result == "My Dashboard"
# Task without resource_name
task2 = MagicMock()
task2.id = "task-456"
task2.params = {}
result2 = service._extract_resource_name_from_task(task2)
assert "task-456" in result2
# [/DEF:test_extract_resource_name_from_task:Function]
# [/DEF:backend.src.services.__tests__.test_resource_service:Module]