# #region Test.ProfileService [C:3] [TYPE Module] [SEMANTICS test,profile,facade,delegate] # @BRIEF Tests for services/profile_service.py — ProfileService facade that delegates to # ProfilePreferenceService, SupersetLookupService, and SecurityBadgeService. # @RELATION BINDS_TO -> [ProfileService] # @TEST_EDGE: missing_field -> empty/none username returns False from matches_dashboard_actor # @TEST_EDGE: invalid_type -> mixed owners payload handled correctly # @TEST_EDGE: delegation -> facade methods call sub-services and return their results from pathlib import Path import sys sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src")) from unittest.mock import AsyncMock, MagicMock, patch import pytest from src.schemas.profile import ProfilePreferenceUpdateRequest, SupersetAccountLookupRequest class _MockUser: def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) class TestProfileServiceInit: """ProfileService __init__ — creates sub-services.""" @patch("src.services.profile_service.ProfilePreferenceService") @patch("src.services.profile_service.SupersetLookupService") @patch("src.services.profile_service.SecurityBadgeService") def test_init_creates_sub_services(self, MockBadge, MockLookup, MockPref): from src.services.profile_service import ProfileService db = MagicMock() config = MagicMock() loader = MagicMock() svc = ProfileService(db, config, loader) MockPref.assert_called_once_with(db, config, loader) MockLookup.assert_called_once_with(config) MockBadge.assert_called_once_with(loader) assert svc.db is db assert svc.config_manager is config assert svc.plugin_loader is loader @patch("src.services.profile_service.ProfilePreferenceService") @patch("src.services.profile_service.SupersetLookupService") @patch("src.services.profile_service.SecurityBadgeService") def test_init_without_plugin_loader(self, MockBadge, MockLookup, MockPref): from src.services.profile_service import ProfileService db = MagicMock() config = MagicMock() svc = ProfileService(db, config) MockBadge.assert_called_once_with(None) class TestProfileServiceDelegation: """ProfileService delegates to sub-services.""" @pytest.fixture def service(self): from src.services.profile_service import ProfileService svc = ProfileService.__new__(ProfileService) svc.preference_service = MagicMock() svc.lookup_service = AsyncMock() svc.security_badge_service = MagicMock() svc.db = MagicMock() svc.config_manager = MagicMock() svc.plugin_loader = MagicMock() return svc def test_get_my_preference_delegates(self, service): user = _MockUser(id="u-1") expected = MagicMock() service.preference_service.get_my_preference.return_value = expected result = service.get_my_preference(user) assert result is expected service.preference_service.get_my_preference.assert_called_once_with(user) def test_get_dashboard_filter_binding_delegates(self, service): user = _MockUser(id="u-1") expected = {"show_only_my_dashboards": True} service.preference_service.get_dashboard_filter_binding.return_value = expected result = service.get_dashboard_filter_binding(user) assert result == expected service.preference_service.get_dashboard_filter_binding.assert_called_once_with(user) def test_update_my_preference_delegates(self, service): user = _MockUser(id="u-1") payload = ProfilePreferenceUpdateRequest(superset_username="jdoe") expected = MagicMock() service.preference_service.update_my_preference.return_value = expected result = service.update_my_preference(user, payload) assert result is expected service.preference_service.update_my_preference.assert_called_once_with(user, payload, None) def test_update_my_preference_with_target_user(self, service): user = _MockUser(id="u-1") payload = ProfilePreferenceUpdateRequest(superset_username="jdoe") service.update_my_preference(user, payload, target_user_id="u-2") service.preference_service.update_my_preference.assert_called_once_with(user, payload, "u-2") @pytest.mark.asyncio async def test_lookup_superset_accounts_delegates(self, service): user = _MockUser(id="u-1") request = SupersetAccountLookupRequest(environment_id="env-1") expected = MagicMock() service.lookup_service.lookup_superset_accounts.return_value = expected result = await service.lookup_superset_accounts(user, request) assert result is expected service.lookup_service.lookup_superset_accounts.assert_called_once_with(user, request) class TestMatchesDashboardActor: """ProfileService.matches_dashboard_actor — normalize + match logic.""" @pytest.fixture def service(self): from src.services.profile_service import ProfileService return ProfileService.__new__(ProfileService) def test_none_username_returns_false(self, service): assert service.matches_dashboard_actor(None, [], None) is False def test_empty_username_returns_false(self, service): assert service.matches_dashboard_actor("", [], None) is False def test_matches_owner_username(self, service): owners = [{"username": "AdminUser"}] assert service.matches_dashboard_actor("adminuser", owners, None) is True def test_matches_modified_by(self, service): assert service.matches_dashboard_actor("admin", None, "Admin") is True def test_no_match_returns_false(self, service): owners = [{"username": "OtherUser"}] assert service.matches_dashboard_actor("admin", owners, "Other") is False def test_matches_with_case_insensitive(self, service): owners = [{"username": "John.Doe"}] assert service.matches_dashboard_actor("john.doe", owners, None) is True def test_owner_tokens_with_full_name(self, service): owners = [{"first_name": "John", "last_name": "Doe"}] assert service.matches_dashboard_actor("john_doe", owners, None) is True def test_empty_owners_list(self, service): assert service.matches_dashboard_actor("admin", [], None) is False # #endregion Test.ProfileService