"""Test logic for admin identity queries.""" from unittest import mock import pytest from permissions.logic import admin_identity_queries from permissions.types import Tenant, TenantType @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_success(db_session_mock: mock.MagicMock) -> None: """Test get_identity_ids_for_external_admin returns identity IDs.""" admin_identity_id = 'admin-uuid' identity_ids = ['user-1', 'user-2', 'user-3'] count_result = mock.Mock() count_result.single.return_value = {'total': 3} data_records = [ {'identity_id': 'user-1'}, {'identity_id': 'user-2'}, {'identity_id': 'user-3'}, ] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, ) assert result == {'total': 3, 'identity_ids': identity_ids} assert session_mock.run.call_count == 2 @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_no_results(db_session_mock: mock.MagicMock) -> None: """Test get_identity_ids_for_external_admin when no identities found.""" admin_identity_id = 'admin-uuid' count_result = mock.Mock() count_result.single.return_value = {'total': 0} session_mock = mock.Mock() session_mock.run.return_value = count_result db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, ) assert result == {'total': 0, 'identity_ids': []} assert session_mock.run.call_count == 1 @pytest.mark.parametrize( ('active', 'expected_relationship'), [ pytest.param('Y', 'HAS_ACCESS_TO|HAS_ADMIN_ACCESS_TO', id='active users'), pytest.param('N', 'DELETED_HAS_ACCESS_TO|DELETED_HAS_ADMIN_ACCESS_TO', id='inactive users'), pytest.param(None, 'HAS_ACCESS_TO|HAS_ADMIN_ACCESS_TO', id='no filter defaults to active'), ], ) @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_active_filter( db_session_mock: mock.MagicMock, active: str | None, expected_relationship: str, ) -> None: """Test get_identity_ids_for_external_admin filters by active status.""" admin_identity_id = 'admin-uuid' count_result = mock.Mock() count_result.single.return_value = {'total': 1} data_records = [{'identity_id': 'user-1'}] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, active=active, ) assert result == {'total': 1, 'identity_ids': ['user-1']} count_call_args = session_mock.run.call_args_list[0] query = count_call_args[0][0] assert expected_relationship in query @pytest.mark.parametrize( ('pending', 'expected_condition'), [ pytest.param('Y', 'user.id = user.auth0UserId', id='pending users only'), pytest.param('N', 'NOT user.id = user.auth0UserId', id='accepted users only'), ], ) @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_pending_filter( db_session_mock: mock.MagicMock, pending: str, expected_condition: str, ) -> None: """Test get_identity_ids_for_external_admin filters by pending status.""" admin_identity_id = 'admin-uuid' count_result = mock.Mock() count_result.single.return_value = {'total': 1} data_records = [{'identity_id': 'user-1'}] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, pending=pending, ) assert result == {'total': 1, 'identity_ids': ['user-1']} count_call_args = session_mock.run.call_args_list[0] query = count_call_args[0][0] assert expected_condition in query @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_search_term( db_session_mock: mock.MagicMock, ) -> None: """Test get_identity_ids_for_external_admin filters by search term.""" admin_identity_id = 'admin-uuid' search_term = 'john doe' count_result = mock.Mock() count_result.single.return_value = {'total': 1} data_records = [{'identity_id': 'user-1'}] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, search_term=search_term, ) assert result == {'total': 1, 'identity_ids': ['user-1']} count_call_args = session_mock.run.call_args_list[0] query = count_call_args[0][0] params = count_call_args[1] assert 'toLower(user.email) CONTAINS $search_term' in query assert params['search_term'] == 'john doe' @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_resource_access( db_session_mock: mock.MagicMock, ) -> None: """Test get_identity_ids_for_external_admin filters by tenant_access.""" admin_identity_id = 'admin-uuid' tenant_access = [ Tenant(tenant_type=TenantType.ACCOUNT, tenant_uuid='tenant-1'), Tenant(tenant_type=TenantType.SUBACCOUNT, tenant_uuid='tenant-2'), ] count_result = mock.Mock() count_result.single.return_value = {'total': 2} data_records = [ {'identity_id': 'user-1'}, {'identity_id': 'user-2'}, ] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, tenant_access=tenant_access, ) assert result == {'total': 2, 'identity_ids': ['user-1', 'user-2']} count_call_args = session_mock.run.call_args_list[0] query = count_call_args[0][0] params = count_call_args[1] assert 'any(tf IN $tenant_filters' in query assert params['tenant_filters'] == [ {'uuid': 'tenant-1', 'label': 'Vendor'}, {'uuid': 'tenant-2', 'label': 'Subaccount'}, ] @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_pagination( db_session_mock: mock.MagicMock, ) -> None: """Test get_identity_ids_for_external_admin respects pagination parameters.""" admin_identity_id = 'admin-uuid' limit = 10 offset = 20 count_result = mock.Mock() count_result.single.return_value = {'total': 100} data_records = [{'identity_id': f'user-{i}'} for i in range(10)] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, limit=limit, offset=offset, ) assert result['total'] == 100 assert len(result['identity_ids']) == 10 data_call_args = session_mock.run.call_args_list[1] params = data_call_args[1] assert params['limit'] == limit assert params['offset'] == offset @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_excludes_admin( db_session_mock: mock.MagicMock, ) -> None: """Test get_identity_ids_for_external_admin excludes the admin from results.""" admin_identity_id = 'admin-uuid' count_result = mock.Mock() count_result.single.return_value = {'total': 2} data_records = [ {'identity_id': 'user-1'}, {'identity_id': 'user-2'}, ] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, ) assert result == {'total': 2, 'identity_ids': ['user-1', 'user-2']} count_call_args = session_mock.run.call_args_list[0] query = count_call_args[0][0] params = count_call_args[1] assert 'user.id <> $admin_identity_id' in query assert params['admin_identity_id'] == admin_identity_id @mock.patch('permissions.connectors.neo4j.db_session') def test_get_identity_ids_for_external_admin_checks_admin_access( db_session_mock: mock.MagicMock, ) -> None: """Test get_identity_ids_for_external_admin verifies admin has HAS_ADMIN_ACCESS_TO.""" admin_identity_id = 'admin-uuid' count_result = mock.Mock() count_result.single.return_value = {'total': 1} data_records = [{'identity_id': 'user-1'}] session_mock = mock.Mock() session_mock.run.side_effect = [count_result, data_records] db_session_mock.return_value.__enter__.return_value = session_mock result = admin_identity_queries.get_identity_ids_for_external_admin( admin_identity_id=admin_identity_id, ) assert result == {'total': 1, 'identity_ids': ['user-1']} count_call_args = session_mock.run.call_args_list[0] query = count_call_args[0][0] assert 'HAS_ADMIN_ACCESS_TO' in query assert "profileType: 'SettingsProfile'" in query