# [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]