# #region Test.Api.DashboardProjection [C:3] [TYPE Module] [SEMANTICS test,dashboard,projection] # @BRIEF Unit tests for dashboard projection/profile helpers. # @RELATION BINDS_TO -> [DashboardProjection] # @TEST_EDGE: owner_normalization # @TEST_EDGE: profile_filter_binding # @TEST_EDGE: task_matching import sys from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch import pytest _src = str(Path(__file__).resolve().parent.parent.parent / "src") if _src not in sys.path: sys.path.insert(0, _src) # ── _normalize_actor_alias_token ── class TestNormalizeActorAliasToken: def test_none_value(self): from src.api.routes.dashboards._projection import _normalize_actor_alias_token assert _normalize_actor_alias_token(None) is None def test_empty_string(self): from src.api.routes.dashboards._projection import _normalize_actor_alias_token assert _normalize_actor_alias_token("") is None def test_whitespace(self): from src.api.routes.dashboards._projection import _normalize_actor_alias_token assert _normalize_actor_alias_token(" ") is None def test_normalized(self): from src.api.routes.dashboards._projection import _normalize_actor_alias_token assert _normalize_actor_alias_token(" Alice ") == "alice" # ── _normalize_owner_display_token ── class TestNormalizeOwnerDisplayToken: def test_none(self): from src.api.routes.dashboards._projection import _normalize_owner_display_token assert _normalize_owner_display_token(None) is None def test_dict_with_username(self): from src.api.routes.dashboards._projection import _normalize_owner_display_token assert _normalize_owner_display_token({"username": "Alice"}) == "Alice" def test_dict_with_full_name(self): from src.api.routes.dashboards._projection import _normalize_owner_display_token assert _normalize_owner_display_token({"full_name": "Alice Smith"}) == "Alice Smith" def test_dict_empty(self): from src.api.routes.dashboards._projection import _normalize_owner_display_token assert _normalize_owner_display_token({}) is None def test_string(self): from src.api.routes.dashboards._projection import _normalize_owner_display_token assert _normalize_owner_display_token("Alice") == "Alice" def test_int(self): from src.api.routes.dashboards._projection import _normalize_owner_display_token assert _normalize_owner_display_token(42) is None # ── _normalize_dashboard_owner_values ── class TestNormalizeDashboardOwnerValues: def test_none(self): from src.api.routes.dashboards._projection import _normalize_dashboard_owner_values assert _normalize_dashboard_owner_values(None) is None def test_list_of_dicts(self): from src.api.routes.dashboards._projection import _normalize_dashboard_owner_values result = _normalize_dashboard_owner_values([ {"username": "Alice"}, {"username": "Bob"}, ]) assert result == ["Alice", "Bob"] def test_single_dict(self): from src.api.routes.dashboards._projection import _normalize_dashboard_owner_values result = _normalize_dashboard_owner_values({"username": "Charlie"}) assert result == ["Charlie"] def test_duplicates_removed(self): from src.api.routes.dashboards._projection import _normalize_dashboard_owner_values result = _normalize_dashboard_owner_values([ {"username": "Alice"}, {"username": "Alice"}, ]) assert result == ["Alice"] # ── _project_dashboard_response_items ── class TestProjectDashboardResponseItems: def test_owners_normalized(self): from src.api.routes.dashboards._projection import _project_dashboard_response_items dashboards = [ {"id": 1, "title": "Main", "owners": [{"username": "Alice"}]}, ] result = _project_dashboard_response_items(dashboards) assert result[0]["owners"] == ["Alice"] def test_empty_list(self): from src.api.routes.dashboards._projection import _project_dashboard_response_items assert _project_dashboard_response_items([]) == [] # ── _get_profile_filter_binding ── class TestGetProfileFilterBinding: def test_uses_get_dashboard_filter_binding(self): from src.api.routes.dashboards._projection import _get_profile_filter_binding profile_service = MagicMock() profile_service.get_dashboard_filter_binding.return_value = { "superset_username": "alice", "superset_username_normalized": "alice", "show_only_my_dashboards": True, "show_only_slug_dashboards": False, } result = _get_profile_filter_binding(profile_service, MagicMock()) assert result["superset_username"] == "alice" assert result["show_only_my_dashboards"] is True def test_uses_get_my_preference_fallback(self): from src.api.routes.dashboards._projection import _get_profile_filter_binding profile_service = MagicMock() # Remove the attribute so hasattr returns False, triggering fallback to get_my_preference del profile_service.get_dashboard_filter_binding pref = MagicMock() pref.preference.superset_username = "bob" pref.preference.superset_username_normalized = "bob" pref.preference.show_only_my_dashboards = True pref.preference.show_only_slug_dashboards = False profile_service.get_my_preference.return_value = pref result = _get_profile_filter_binding(profile_service, MagicMock()) assert result["superset_username"] == "bob" def test_no_methods_returns_defaults(self): from src.api.routes.dashboards._projection import _get_profile_filter_binding profile_service = MagicMock(spec=[]) # no relevant methods result = _get_profile_filter_binding(profile_service, MagicMock()) assert result["superset_username"] is None assert result["show_only_my_dashboards"] is False # ── _resolve_profile_actor_aliases ── class TestResolveProfileActorAliases: @pytest.mark.asyncio async def test_empty_username(self): from src.api.routes.dashboards._projection import _resolve_profile_actor_aliases result = await _resolve_profile_actor_aliases(MagicMock(), "") assert result == [] @pytest.mark.asyncio async def test_lookup_success(self): from src.api.routes.dashboards._projection import _resolve_profile_actor_aliases mock_adapter = AsyncMock() mock_adapter.get_users_page.return_value = { "items": [ {"username": "alice", "display_name": "Alice Smith"}, ] } mock_env = MagicMock() mock_env.id = "env-1" with patch("src.api.routes.dashboards._projection.AsyncSupersetClient") as MockClient, \ patch("src.api.routes.dashboards._projection.SupersetAccountLookupAdapter") as MockAdapter: MockAdapter.return_value = mock_adapter result = await _resolve_profile_actor_aliases(mock_env, "alice") assert "alice" in result assert "alice smith" in result @pytest.mark.asyncio async def test_lookup_exception(self): from src.api.routes.dashboards._projection import _resolve_profile_actor_aliases mock_env = MagicMock() mock_env.id = "env-1" with patch("src.api.routes.dashboards._projection.AsyncSupersetClient") as MockClient, \ patch("src.api.routes.dashboards._projection.SupersetAccountLookupAdapter") as MockAdapter: MockAdapter.side_effect = Exception("Connection error") result = await _resolve_profile_actor_aliases(mock_env, "alice") assert result == ["alice"] # ── _matches_dashboard_actor_aliases ── class TestMatchesDashboardActorAliases: def test_matches(self): from src.api.routes.dashboards._projection import _matches_dashboard_actor_aliases profile_service = MagicMock() profile_service.matches_dashboard_actor.return_value = True assert _matches_dashboard_actor_aliases(profile_service, ["alice"], [], "bob") is True def test_no_match(self): from src.api.routes.dashboards._projection import _matches_dashboard_actor_aliases profile_service = MagicMock() profile_service.matches_dashboard_actor.return_value = False assert _matches_dashboard_actor_aliases(profile_service, ["alice"], [], None) is False def test_first_match_short_circuits(self): from src.api.routes.dashboards._projection import _matches_dashboard_actor_aliases profile_service = MagicMock() profile_service.matches_dashboard_actor.side_effect = [False, True] assert _matches_dashboard_actor_aliases(profile_service, ["alice", "bob"], [], None) is True assert profile_service.matches_dashboard_actor.call_count == 2 # ── _task_matches_dashboard ── class TestTaskMatchesDashboard: def test_llm_validation_matches(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "llm_dashboard_validation" task.params = {"dashboard_id": 42, "environment_id": "env-1"} assert _task_matches_dashboard(task, 42, "env-1") is True def test_llm_validation_wrong_dashboard(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "llm_dashboard_validation" task.params = {"dashboard_id": 99} assert _task_matches_dashboard(task, 42, None) is False def test_llm_validation_no_env(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "llm_dashboard_validation" task.params = {"dashboard_id": 42} assert _task_matches_dashboard(task, 42, None) is True def test_backup_matches(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "superset-backup" task.params = {"dashboard_ids": [1, 42, 3], "environment_id": "env-1"} assert _task_matches_dashboard(task, 42, "env-1") is True def test_backup_dashboards_key(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "superset-backup" task.params = {"dashboards": [42], "env": "env-1"} assert _task_matches_dashboard(task, 42, "env-1") is True def test_unrelated_plugin(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "some-other-plugin" assert _task_matches_dashboard(task, 42, "env-1") is False def test_backup_wrong_dashboard(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "superset-backup" task.params = {"dashboard_ids": [1, 2], "environment_id": "env-1"} assert _task_matches_dashboard(task, 42, "env-1") is False def test_backup_wrong_env(self): from src.api.routes.dashboards._projection import _task_matches_dashboard task = MagicMock() task.plugin_id = "superset-backup" task.params = {"dashboard_ids": [42], "environment_id": "env-1"} assert _task_matches_dashboard(task, 42, "env-2") is False # #endregion Test.Api.DashboardProjection