# [DEF:backend.src.api.routes.__tests__.test_dashboards:Module] # @TIER: STANDARD # @PURPOSE: Unit tests for Dashboards API endpoints # @LAYER: API # @RELATION: TESTS -> backend.src.api.routes.dashboards import pytest from unittest.mock import MagicMock, patch, AsyncMock from datetime import datetime, timezone from fastapi.testclient import TestClient from src.app import app from src.api.routes.dashboards import DashboardsResponse from src.dependencies import get_current_user, has_permission, get_config_manager, get_task_manager, get_resource_service, get_mapping_service from src.core.database import get_db from src.services.profile_service import ProfileService as DomainProfileService # Global mock user for get_current_user dependency overrides mock_user = MagicMock() mock_user.id = "u-1" mock_user.username = "testuser" mock_user.roles = [] admin_role = MagicMock() admin_role.name = "Admin" mock_user.roles.append(admin_role) @pytest.fixture(autouse=True) def mock_deps(): config_manager = MagicMock() task_manager = MagicMock() resource_service = MagicMock() mapping_service = MagicMock() db = MagicMock() app.dependency_overrides[get_config_manager] = lambda: config_manager app.dependency_overrides[get_task_manager] = lambda: task_manager app.dependency_overrides[get_resource_service] = lambda: resource_service app.dependency_overrides[get_mapping_service] = lambda: mapping_service app.dependency_overrides[get_current_user] = lambda: mock_user app.dependency_overrides[get_db] = lambda: db app.dependency_overrides[has_permission("plugin:migration", "READ")] = lambda: mock_user app.dependency_overrides[has_permission("plugin:migration", "EXECUTE")] = lambda: mock_user app.dependency_overrides[has_permission("plugin:backup", "EXECUTE")] = lambda: mock_user app.dependency_overrides[has_permission("tasks", "READ")] = lambda: mock_user yield { "config": config_manager, "task": task_manager, "resource": resource_service, "mapping": mapping_service, "db": db, } app.dependency_overrides.clear() client = TestClient(app) # [DEF:test_get_dashboards_success:Function] # @TEST: GET /api/dashboards returns 200 and valid schema # @PRE: env_id exists # @POST: Response matches DashboardsResponse schema def test_get_dashboards_success(mock_deps): """Uses @TEST_FIXTURE: dashboard_list_happy data.""" mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] # @TEST_FIXTURE: dashboard_list_happy -> {"id": 1, "title": "Main Revenue"} mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[ { "id": 1, "title": "Main Revenue", "slug": "main-revenue", "git_status": {"branch": "main", "sync_status": "OK"}, "last_task": {"task_id": "task-1", "status": "SUCCESS"} } ]) response = client.get("/api/dashboards?env_id=prod") assert response.status_code == 200 data = response.json() # exhaustive @POST assertions assert "dashboards" in data assert len(data["dashboards"]) == 1 assert data["dashboards"][0]["title"] == "Main Revenue" assert data["total"] == 1 assert "page" in data DashboardsResponse(**data) # [/DEF:test_get_dashboards_success:Function] # [DEF:test_get_dashboards_with_search:Function] # @TEST: GET /api/dashboards filters by search term # @PRE: search parameter provided # @POST: Only matching dashboards returned def test_get_dashboards_with_search(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] async def mock_get_dashboards(env, tasks, include_git_status=False): return [ {"id": 1, "title": "Sales Report", "slug": "sales", "git_status": {"branch": "main", "sync_status": "OK"}, "last_task": None}, {"id": 2, "title": "Marketing Dashboard", "slug": "marketing", "git_status": {"branch": "main", "sync_status": "OK"}, "last_task": None} ] mock_deps["resource"].get_dashboards_with_status = AsyncMock( side_effect=mock_get_dashboards ) response = client.get("/api/dashboards?env_id=prod&search=sales") assert response.status_code == 200 data = response.json() # @POST: Filtered result count must match search assert len(data["dashboards"]) == 1 assert data["dashboards"][0]["title"] == "Sales Report" # [/DEF:test_get_dashboards_with_search:Function] # [DEF:test_get_dashboards_empty:Function] # @TEST_EDGE: empty_dashboards -> {env_id: 'empty_env', expected_total: 0} def test_get_dashboards_empty(mock_deps): """@TEST_EDGE: empty_dashboards -> {env_id: 'empty_env', expected_total: 0}""" mock_env = MagicMock() mock_env.id = "empty_env" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[]) response = client.get("/api/dashboards?env_id=empty_env") assert response.status_code == 200 data = response.json() assert data["total"] == 0 assert len(data["dashboards"]) == 0 assert data["total_pages"] == 1 DashboardsResponse(**data) # [/DEF:test_get_dashboards_empty:Function] # [DEF:test_get_dashboards_superset_failure:Function] # @TEST_EDGE: external_superset_failure -> {env_id: 'bad_conn', status: 503} def test_get_dashboards_superset_failure(mock_deps): """@TEST_EDGE: external_superset_failure -> {env_id: 'bad_conn', status: 503}""" mock_env = MagicMock() mock_env.id = "bad_conn" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock( side_effect=Exception("Connection refused") ) response = client.get("/api/dashboards?env_id=bad_conn") assert response.status_code == 503 assert "Failed to fetch dashboards" in response.json()["detail"] # [/DEF:test_get_dashboards_superset_failure:Function] # [DEF:test_get_dashboards_env_not_found:Function] # @TEST: GET /api/dashboards returns 404 if env_id missing # @PRE: env_id does not exist # @POST: Returns 404 error def test_get_dashboards_env_not_found(mock_deps): mock_deps["config"].get_environments.return_value = [] response = client.get("/api/dashboards?env_id=nonexistent") assert response.status_code == 404 assert "Environment not found" in response.json()["detail"] # [/DEF:test_get_dashboards_env_not_found:Function] # [DEF:test_get_dashboards_invalid_pagination:Function] # @TEST: GET /api/dashboards returns 400 for invalid page/page_size # @PRE: page < 1 or page_size > 100 # @POST: Returns 400 error def test_get_dashboards_invalid_pagination(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] # Invalid page response = client.get("/api/dashboards?env_id=prod&page=0") assert response.status_code == 400 assert "Page must be >= 1" in response.json()["detail"] # Invalid page_size response = client.get("/api/dashboards?env_id=prod&page_size=101") assert response.status_code == 400 assert "Page size must be between 1 and 100" in response.json()["detail"] # [/DEF:test_get_dashboards_invalid_pagination:Function] # [DEF:test_get_dashboard_detail_success:Function] # @TEST: GET /api/dashboards/{id} returns dashboard detail with charts and datasets def test_get_dashboard_detail_success(mock_deps): with patch("src.api.routes.dashboards.SupersetClient") as mock_client_cls: mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_client = MagicMock() mock_client.get_dashboard_detail.return_value = { "id": 42, "title": "Revenue Dashboard", "slug": "revenue-dashboard", "url": "/superset/dashboard/42/", "description": "Overview", "last_modified": "2026-02-20T10:00:00+00:00", "published": True, "charts": [ { "id": 100, "title": "Revenue by Month", "viz_type": "line", "dataset_id": 7, "last_modified": "2026-02-19T10:00:00+00:00", "overview": "line" } ], "datasets": [ { "id": 7, "table_name": "fact_revenue", "schema": "mart", "database": "Analytics", "last_modified": "2026-02-18T10:00:00+00:00", "overview": "mart.fact_revenue" } ], "chart_count": 1, "dataset_count": 1 } mock_client_cls.return_value = mock_client response = client.get("/api/dashboards/42?env_id=prod") assert response.status_code == 200 payload = response.json() assert payload["id"] == 42 assert payload["chart_count"] == 1 assert payload["dataset_count"] == 1 # [/DEF:test_get_dashboard_detail_success:Function] # [DEF:test_get_dashboard_detail_env_not_found:Function] # @TEST: GET /api/dashboards/{id} returns 404 for missing environment def test_get_dashboard_detail_env_not_found(mock_deps): mock_deps["config"].get_environments.return_value = [] response = client.get("/api/dashboards/42?env_id=missing") assert response.status_code == 404 assert "Environment not found" in response.json()["detail"] # [/DEF:test_get_dashboard_detail_env_not_found:Function] # [DEF:test_migrate_dashboards_success:Function] # @TEST: POST /api/dashboards/migrate creates migration task # @PRE: Valid source_env_id, target_env_id, dashboard_ids # @POST: Returns task_id and create_task was called def test_migrate_dashboards_success(mock_deps): mock_source = MagicMock() mock_source.id = "source" mock_target = MagicMock() mock_target.id = "target" mock_deps["config"].get_environments.return_value = [mock_source, mock_target] mock_task = MagicMock() mock_task.id = "task-migrate-123" mock_deps["task"].create_task = AsyncMock(return_value=mock_task) response = client.post( "/api/dashboards/migrate", json={ "source_env_id": "source", "target_env_id": "target", "dashboard_ids": [1, 2, 3], "db_mappings": {"old_db": "new_db"} } ) assert response.status_code == 200 data = response.json() assert "task_id" in data # @POST/@SIDE_EFFECT: create_task was called mock_deps["task"].create_task.assert_called_once() # [/DEF:test_migrate_dashboards_success:Function] # [DEF:test_migrate_dashboards_no_ids:Function] # @TEST: POST /api/dashboards/migrate returns 400 for empty dashboard_ids # @PRE: dashboard_ids is empty # @POST: Returns 400 error def test_migrate_dashboards_no_ids(mock_deps): response = client.post( "/api/dashboards/migrate", json={ "source_env_id": "source", "target_env_id": "target", "dashboard_ids": [] } ) assert response.status_code == 400 assert "At least one dashboard ID must be provided" in response.json()["detail"] # [/DEF:test_migrate_dashboards_no_ids:Function] # [DEF:test_migrate_dashboards_env_not_found:Function] # @PRE: source_env_id and target_env_id are valid environment IDs def test_migrate_dashboards_env_not_found(mock_deps): """@PRE: source_env_id and target_env_id are valid environment IDs.""" mock_deps["config"].get_environments.return_value = [] response = client.post( "/api/dashboards/migrate", json={ "source_env_id": "ghost", "target_env_id": "t", "dashboard_ids": [1] } ) assert response.status_code == 404 assert "Source environment not found" in response.json()["detail"] # [/DEF:test_migrate_dashboards_env_not_found:Function] # [DEF:test_backup_dashboards_success:Function] # @TEST: POST /api/dashboards/backup creates backup task # @PRE: Valid env_id, dashboard_ids # @POST: Returns task_id and create_task was called def test_backup_dashboards_success(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_task = MagicMock() mock_task.id = "task-backup-456" mock_deps["task"].create_task = AsyncMock(return_value=mock_task) response = client.post( "/api/dashboards/backup", json={ "env_id": "prod", "dashboard_ids": [1, 2, 3], "schedule": "0 0 * * *" } ) assert response.status_code == 200 data = response.json() assert "task_id" in data # @POST/@SIDE_EFFECT: create_task was called mock_deps["task"].create_task.assert_called_once() # [/DEF:test_backup_dashboards_success:Function] # [DEF:test_backup_dashboards_env_not_found:Function] # @PRE: env_id is a valid environment ID def test_backup_dashboards_env_not_found(mock_deps): """@PRE: env_id is a valid environment ID.""" mock_deps["config"].get_environments.return_value = [] response = client.post( "/api/dashboards/backup", json={ "env_id": "ghost", "dashboard_ids": [1] } ) assert response.status_code == 404 assert "Environment not found" in response.json()["detail"] # [/DEF:test_backup_dashboards_env_not_found:Function] # [DEF:test_get_database_mappings_success:Function] # @TEST: GET /api/dashboards/db-mappings returns mapping suggestions # @PRE: Valid source_env_id, target_env_id # @POST: Returns list of database mappings def test_get_database_mappings_success(mock_deps): mock_source = MagicMock() mock_source.id = "prod" mock_target = MagicMock() mock_target.id = "staging" mock_deps["config"].get_environments.return_value = [mock_source, mock_target] mock_deps["mapping"].get_suggestions = AsyncMock(return_value=[ { "source_db": "old_sales", "target_db": "new_sales", "source_db_uuid": "uuid-1", "target_db_uuid": "uuid-2", "confidence": 0.95 } ]) response = client.get("/api/dashboards/db-mappings?source_env_id=prod&target_env_id=staging") assert response.status_code == 200 data = response.json() assert "mappings" in data assert len(data["mappings"]) == 1 assert data["mappings"][0]["confidence"] == 0.95 # [/DEF:test_get_database_mappings_success:Function] # [DEF:test_get_database_mappings_env_not_found:Function] # @PRE: source_env_id and target_env_id are valid environment IDs def test_get_database_mappings_env_not_found(mock_deps): """@PRE: source_env_id must be a valid environment.""" mock_deps["config"].get_environments.return_value = [] response = client.get("/api/dashboards/db-mappings?source_env_id=ghost&target_env_id=t") assert response.status_code == 404 # [/DEF:test_get_database_mappings_env_not_found:Function] # [DEF:test_get_dashboard_tasks_history_filters_success:Function] # @TEST: GET /api/dashboards/{id}/tasks returns backup and llm tasks for dashboard def test_get_dashboard_tasks_history_filters_success(mock_deps): now = datetime.now(timezone.utc) llm_task = MagicMock() llm_task.id = "task-llm-1" llm_task.plugin_id = "llm_dashboard_validation" llm_task.status = "SUCCESS" llm_task.started_at = now llm_task.finished_at = now llm_task.params = {"dashboard_id": "42", "environment_id": "prod"} llm_task.result = {"summary": "LLM validation complete"} backup_task = MagicMock() backup_task.id = "task-backup-1" backup_task.plugin_id = "superset-backup" backup_task.status = "RUNNING" backup_task.started_at = now backup_task.finished_at = None backup_task.params = {"env": "prod", "dashboards": [42]} backup_task.result = {} other_task = MagicMock() other_task.id = "task-other" other_task.plugin_id = "superset-backup" other_task.status = "SUCCESS" other_task.started_at = now other_task.finished_at = now other_task.params = {"env": "prod", "dashboards": [777]} other_task.result = {} mock_deps["task"].get_all_tasks.return_value = [other_task, llm_task, backup_task] response = client.get("/api/dashboards/42/tasks?env_id=prod&limit=10") assert response.status_code == 200 data = response.json() assert data["dashboard_id"] == 42 assert len(data["items"]) == 2 assert {item["plugin_id"] for item in data["items"]} == {"llm_dashboard_validation", "superset-backup"} # [/DEF:test_get_dashboard_tasks_history_filters_success:Function] # [DEF:test_get_dashboard_thumbnail_success:Function] # @TEST: GET /api/dashboards/{id}/thumbnail proxies image bytes from Superset def test_get_dashboard_thumbnail_success(mock_deps): with patch("src.api.routes.dashboards.SupersetClient") as mock_client_cls: mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_client = MagicMock() mock_response = MagicMock() mock_response.status_code = 200 mock_response.content = b"fake-image-bytes" mock_response.headers = {"Content-Type": "image/png"} def _network_request(method, endpoint, **kwargs): if method == "POST": return {"image_url": "/api/v1/dashboard/42/screenshot/abc123/"} return mock_response mock_client.network.request.side_effect = _network_request mock_client_cls.return_value = mock_client response = client.get("/api/dashboards/42/thumbnail?env_id=prod") assert response.status_code == 200 assert response.content == b"fake-image-bytes" assert response.headers["content-type"].startswith("image/png") # [/DEF:test_get_dashboard_thumbnail_success:Function] # [DEF:_build_profile_preference_stub:Function] # @PURPOSE: Creates profile preference payload stub for dashboards filter contract tests. # @PRE: username can be empty; enabled indicates profile-default toggle state. # @POST: Returns object compatible with ProfileService.get_my_preference contract. def _build_profile_preference_stub(username: str, enabled: bool): preference = MagicMock() preference.superset_username = username preference.superset_username_normalized = str(username or "").strip().lower() or None preference.show_only_my_dashboards = bool(enabled) payload = MagicMock() payload.preference = preference return payload # [/DEF:_build_profile_preference_stub:Function] # [DEF:_matches_actor_case_insensitive:Function] # @PURPOSE: Applies trim + case-insensitive owners OR modified_by matching used by route contract tests. # @PRE: owners can be None or list-like values. # @POST: Returns True when bound username matches any owner or modified_by. def _matches_actor_case_insensitive(bound_username, owners, modified_by): normalized_bound = str(bound_username or "").strip().lower() if not normalized_bound: return False owner_tokens = [] for owner in owners or []: token = str(owner or "").strip().lower() if token: owner_tokens.append(token) modified_token = str(modified_by or "").strip().lower() return normalized_bound in owner_tokens or bool(modified_token and modified_token == normalized_bound) # [/DEF:_matches_actor_case_insensitive:Function] # [DEF:test_get_dashboards_profile_filter_contract_owners_or_modified_by:Function] # @TEST: GET /api/dashboards applies profile-default filter with owners OR modified_by trim+case-insensitive semantics. # @PRE: Current user has enabled profile-default preference and bound username. # @POST: Response includes only matching dashboards and effective_profile_filter metadata. def test_get_dashboards_profile_filter_contract_owners_or_modified_by(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[ { "id": 1, "title": "Owner Match", "slug": "owner-match", "owners": [" John_Doe "], "modified_by": "someone_else", }, { "id": 2, "title": "Modifier Match", "slug": "modifier-match", "owners": ["analytics-team"], "modified_by": " JOHN_DOE ", }, { "id": 3, "title": "No Match", "slug": "no-match", "owners": ["another-user"], "modified_by": "nobody", }, ]) with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls: profile_service = MagicMock() profile_service.get_my_preference.return_value = _build_profile_preference_stub( username=" JOHN_DOE ", enabled=True, ) profile_service.matches_dashboard_actor.side_effect = _matches_actor_case_insensitive profile_service_cls.return_value = profile_service response = client.get( "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true" ) assert response.status_code == 200 payload = response.json() assert payload["total"] == 2 assert {item["id"] for item in payload["dashboards"]} == {1, 2} assert payload["effective_profile_filter"]["applied"] is True assert payload["effective_profile_filter"]["source_page"] == "dashboards_main" assert payload["effective_profile_filter"]["override_show_all"] is False assert payload["effective_profile_filter"]["username"] == "john_doe" assert payload["effective_profile_filter"]["match_logic"] == "owners_or_modified_by" # [/DEF:test_get_dashboards_profile_filter_contract_owners_or_modified_by:Function] # [DEF:test_get_dashboards_override_show_all_contract:Function] # @TEST: GET /api/dashboards honors override_show_all and disables profile-default filter for current page. # @PRE: Profile-default preference exists but override_show_all=true query is provided. # @POST: Response remains unfiltered and effective_profile_filter.applied is false. def test_get_dashboards_override_show_all_contract(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[ {"id": 1, "title": "Dash A", "slug": "dash-a", "owners": ["john_doe"], "modified_by": "john_doe"}, {"id": 2, "title": "Dash B", "slug": "dash-b", "owners": ["other"], "modified_by": "other"}, ]) with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls: profile_service = MagicMock() profile_service.get_my_preference.return_value = _build_profile_preference_stub( username="john_doe", enabled=True, ) profile_service.matches_dashboard_actor.side_effect = _matches_actor_case_insensitive profile_service_cls.return_value = profile_service response = client.get( "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true&override_show_all=true" ) assert response.status_code == 200 payload = response.json() assert payload["total"] == 2 assert {item["id"] for item in payload["dashboards"]} == {1, 2} assert payload["effective_profile_filter"]["applied"] is False assert payload["effective_profile_filter"]["source_page"] == "dashboards_main" assert payload["effective_profile_filter"]["override_show_all"] is True assert payload["effective_profile_filter"]["username"] is None assert payload["effective_profile_filter"]["match_logic"] is None profile_service.matches_dashboard_actor.assert_not_called() # [/DEF:test_get_dashboards_override_show_all_contract:Function] # [DEF:test_get_dashboards_profile_filter_no_match_results_contract:Function] # @TEST: GET /api/dashboards returns empty result set when profile-default filter is active and no dashboard actors match. # @PRE: Profile-default preference is enabled with bound username and all dashboards are non-matching. # @POST: Response total is 0 with deterministic pagination and active effective_profile_filter metadata. def test_get_dashboards_profile_filter_no_match_results_contract(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[ { "id": 101, "title": "Team Dashboard", "slug": "team-dashboard", "owners": ["analytics-team"], "modified_by": "someone_else", }, { "id": 102, "title": "Ops Dashboard", "slug": "ops-dashboard", "owners": ["ops-user"], "modified_by": "ops-user", }, ]) with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls: profile_service = MagicMock() profile_service.get_my_preference.return_value = _build_profile_preference_stub( username="john_doe", enabled=True, ) profile_service.matches_dashboard_actor.side_effect = _matches_actor_case_insensitive profile_service_cls.return_value = profile_service response = client.get( "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true" ) assert response.status_code == 200 payload = response.json() assert payload["total"] == 0 assert payload["dashboards"] == [] assert payload["page"] == 1 assert payload["page_size"] == 10 assert payload["total_pages"] == 1 assert payload["effective_profile_filter"]["applied"] is True assert payload["effective_profile_filter"]["source_page"] == "dashboards_main" assert payload["effective_profile_filter"]["override_show_all"] is False assert payload["effective_profile_filter"]["username"] == "john_doe" assert payload["effective_profile_filter"]["match_logic"] == "owners_or_modified_by" # [/DEF:test_get_dashboards_profile_filter_no_match_results_contract:Function] # [DEF:test_get_dashboards_page_context_other_disables_profile_default:Function] # @TEST: GET /api/dashboards does not auto-apply profile-default filter outside dashboards_main page context. # @PRE: Profile-default preference exists but page_context=other query is provided. # @POST: Response remains unfiltered and metadata reflects source_page=other. def test_get_dashboards_page_context_other_disables_profile_default(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[ {"id": 1, "title": "Dash A", "slug": "dash-a", "owners": ["john_doe"], "modified_by": "john_doe"}, {"id": 2, "title": "Dash B", "slug": "dash-b", "owners": ["other"], "modified_by": "other"}, ]) with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls: profile_service = MagicMock() profile_service.get_my_preference.return_value = _build_profile_preference_stub( username="john_doe", enabled=True, ) profile_service.matches_dashboard_actor.side_effect = _matches_actor_case_insensitive profile_service_cls.return_value = profile_service response = client.get( "/api/dashboards?env_id=prod&page_context=other&apply_profile_default=true" ) assert response.status_code == 200 payload = response.json() assert payload["total"] == 2 assert {item["id"] for item in payload["dashboards"]} == {1, 2} assert payload["effective_profile_filter"]["applied"] is False assert payload["effective_profile_filter"]["source_page"] == "other" assert payload["effective_profile_filter"]["override_show_all"] is False assert payload["effective_profile_filter"]["username"] is None assert payload["effective_profile_filter"]["match_logic"] is None profile_service.matches_dashboard_actor.assert_not_called() # [/DEF:test_get_dashboards_page_context_other_disables_profile_default:Function] # [DEF:test_get_dashboards_profile_filter_matches_display_alias_without_detail_fanout:Function] # @TEST: GET /api/dashboards resolves Superset display-name alias once and filters without per-dashboard detail calls. # @PRE: Profile-default filter is active, bound username is `admin`, dashboard actors contain display labels. # @POST: Route matches by alias (`Superset Admin`) and does not call `SupersetClient.get_dashboard` in list filter path. def test_get_dashboards_profile_filter_matches_display_alias_without_detail_fanout(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[ { "id": 5, "title": "Alias Match", "slug": "alias-match", "owners": [], "created_by": None, "modified_by": "Superset Admin", }, { "id": 6, "title": "Alias No Match", "slug": "alias-no-match", "owners": [], "created_by": None, "modified_by": "Other User", }, ]) with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls, patch( "src.api.routes.dashboards.SupersetClient" ) as superset_client_cls, patch( "src.api.routes.dashboards.SupersetAccountLookupAdapter" ) as lookup_adapter_cls: profile_service = MagicMock() profile_service.get_my_preference.return_value = _build_profile_preference_stub( username="admin", enabled=True, ) profile_service.matches_dashboard_actor.side_effect = _matches_actor_case_insensitive profile_service_cls.return_value = profile_service superset_client = MagicMock() superset_client_cls.return_value = superset_client lookup_adapter = MagicMock() lookup_adapter.get_users_page.return_value = { "items": [ { "environment_id": "prod", "username": "admin", "display_name": "Superset Admin", "email": "admin@example.com", "is_active": True, } ], "total": 1, } lookup_adapter_cls.return_value = lookup_adapter response = client.get( "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true" ) assert response.status_code == 200 payload = response.json() assert payload["total"] == 1 assert {item["id"] for item in payload["dashboards"]} == {5} assert payload["effective_profile_filter"]["applied"] is True lookup_adapter.get_users_page.assert_called_once() superset_client.get_dashboard.assert_not_called() # [/DEF:test_get_dashboards_profile_filter_matches_display_alias_without_detail_fanout:Function] # [DEF:test_get_dashboards_profile_filter_matches_owner_object_payload_contract:Function] # @TEST: GET /api/dashboards profile-default filter matches Superset owner object payloads. # @PRE: Profile-default preference is enabled and owners list contains dict payloads. # @POST: Response keeps dashboards where owner object resolves to bound username alias. def test_get_dashboards_profile_filter_matches_owner_object_payload_contract(mock_deps): mock_env = MagicMock() mock_env.id = "prod" mock_deps["config"].get_environments.return_value = [mock_env] mock_deps["task"].get_all_tasks.return_value = [] mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[ { "id": 701, "title": "Featured Charts", "slug": "featured-charts", "owners": [ { "id": 11, "first_name": "user", "last_name": "1", "username": None, "email": "user_1@example.local", } ], "modified_by": "another_user", }, { "id": 702, "title": "Other Dashboard", "slug": "other-dashboard", "owners": [ { "id": 12, "first_name": "other", "last_name": "user", "username": None, "email": "other@example.local", } ], "modified_by": "other_user", }, ]) with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls, patch( "src.api.routes.dashboards._resolve_profile_actor_aliases", return_value=["user_1"], ): profile_service = DomainProfileService(db=MagicMock(), config_manager=MagicMock()) profile_service.get_my_preference = MagicMock( return_value=_build_profile_preference_stub( username="user_1", enabled=True, ) ) profile_service_cls.return_value = profile_service response = client.get( "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true" ) assert response.status_code == 200 payload = response.json() assert payload["total"] == 1 assert {item["id"] for item in payload["dashboards"]} == {701} assert payload["dashboards"][0]["title"] == "Featured Charts" # [/DEF:test_get_dashboards_profile_filter_matches_owner_object_payload_contract:Function] # [/DEF:backend.src.api.routes.__tests__.test_dashboards:Module]