"""Tests for seat handlers.""" import json from unittest import mock from flask import testing import pytest @pytest.mark.parametrize( ['identity_id', 'pdp_response', 'search_term', 'expected_status'], [ pytest.param(None, 'aaa', True, 401, id='No valid JWT'), pytest.param( '74165b07-c597-46ba-b64a-21ff3632e843', False, 'aaa', 403, id='Unauthorized user' ), pytest.param('74165b07-c597-46ba-b64a-21ff3632e843', True, None, 400, id='No search term'), pytest.param( '74165b07-c597-46ba-b64a-21ff3632e843', True, '?!', 400, id='Invalid search term' ), pytest.param( '74165b07-c597-46ba-b64a-21ff3632e843', True, 'tomás@dachshund.long', 200, id='Valid request', ), ], ) @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.handlers.internal.identity_model') @mock.patch('users.utils.authorization.pdp_authorize_list_employees') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_seat_users_validation( mock_g: mock.MagicMock, authorization_mock: mock.MagicMock, identity_model_mock: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, identity_id: str | None, pdp_response: bool, search_term: str | None, expected_status: int, fixture_client: testing.FlaskClient, ) -> None: """Test get_seat_users endpoint.""" mock_g.request_context.jwt_identity_id = identity_id authorization_mock.return_value = pdp_response identity_model_mock.get_employees_by_search_term.return_value = [] response = fixture_client.get('/internal/users', query_string={'term': search_term}) assert response.status_code == expected_status @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.handlers.internal.identity_model') @mock.patch('users.utils.authorization.pdp_authorize_list_employees') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_seat_users_success( mock_g: mock.MagicMock, authorization_mock: mock.MagicMock, identity_model_mock: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, fixture_client: testing.FlaskClient, ) -> None: """Test get_seat_users endpoint success case.""" mock_g.request_context.jwt_identity_id = '74165b07-c597-46ba-b64a-21ff3632e843' authorization_mock.return_value = True identity_model_mock.get_employees_by_search_term.return_value = ['user1', 'user2'] response = fixture_client.get('/internal/users', query_string={'term': 'kat dog'}) assert response.status_code == 200 assert response.json == {'users': ['user1', 'user2']} authorization_mock.assert_called_once_with() identity_model_mock.get_employees_by_search_term.assert_called_once_with('kat dog') @pytest.mark.parametrize( ['identity_id', 'pdp_response', 'expected_status'], [ pytest.param(None, True, 401, id='No valid JWT'), pytest.param('74165b07-c597-46ba-b64a-21ff3632e843', False, 403, id='Unauthorized user'), pytest.param('74165b07-c597-46ba-b64a-21ff3632e843', True, 200, id='Valid request'), ], ) @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.handlers.internal.identity_model') @mock.patch('users.utils.authorization.pdp_authorize_list_employees') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_employee_by_email_authorization( mock_g: mock.MagicMock, authorization_mock: mock.MagicMock, identity_model_mock: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, identity_id: str | None, pdp_response: bool, expected_status: int, fixture_client: testing.FlaskClient, ) -> None: """Test get_employee_by_email endpoint authorization.""" mock_g.request_context.jwt_identity_id = identity_id authorization_mock.return_value = pdp_response identity_model_mock.get_identity_id_by_email.return_value = 'test-identity-uuid' response = fixture_client.post( '/internal/user/get_by_email', json={'email': 'test@sonymusic.com'} ) assert response.status_code == expected_status @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.handlers.internal.identity_model') @mock.patch('users.utils.authorization.pdp_authorize_list_employees') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_employee_by_email_returns_identity_id( mock_g: mock.MagicMock, authorization_mock: mock.MagicMock, identity_model_mock: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, fixture_client: testing.FlaskClient, ) -> None: """Test get_employee_by_email returns the identity ID when found.""" mock_g.request_context.jwt_identity_id = '74165b07-c597-46ba-b64a-21ff3632e843' authorization_mock.return_value = True identity_model_mock.get_identity_id_by_email.return_value = 'found-identity-uuid' response = fixture_client.post( '/internal/user/get_by_email', json={'email': 'john.doe@sonymusic.com'} ) assert response.status_code == 200 assert response.json == {'id': 'found-identity-uuid'} authorization_mock.assert_called_once_with() identity_model_mock.get_identity_id_by_email.assert_called_once_with('john.doe@sonymusic.com') @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.handlers.internal.identity_model') @mock.patch('users.utils.authorization.pdp_authorize_list_employees') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_employee_by_email_not_found( mock_g: mock.MagicMock, authorization_mock: mock.MagicMock, identity_model_mock: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, fixture_client: testing.FlaskClient, ) -> None: """Test get_employee_by_email returns 404 when identity not found.""" mock_g.request_context.jwt_identity_id = '74165b07-c597-46ba-b64a-21ff3632e843' authorization_mock.return_value = True identity_model_mock.get_identity_id_by_email.return_value = None response = fixture_client.post( '/internal/user/get_by_email', json={'email': 'notfound@sonymusic.com'} ) assert response.status_code == 404 assert response.json['message'] == 'Identity not found' identity_model_mock.get_identity_id_by_email.assert_called_once_with('notfound@sonymusic.com') @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_employee_by_email_missing_email( mock_g: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, fixture_client: testing.FlaskClient, ) -> None: """Test get_employee_by_email returns 400 when email is missing.""" mock_g.request_context.jwt_identity_id = '74165b07-c597-46ba-b64a-21ff3632e843' response = fixture_client.post('/internal/user/get_by_email', json={}) assert response.status_code == 400 result = json.loads(response.data.decode()) assert result['code'] == 'validation_error' assert result['message'] == {'email': ['Missing data for required field.']} @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_employee_by_email_invalid_domain( mock_g: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, fixture_client: testing.FlaskClient, ) -> None: """Test get_employee_by_email returns 400 when email domain is invalid.""" mock_g.request_context.jwt_identity_id = '74165b07-c597-46ba-b64a-21ff3632e843' response = fixture_client.post('/internal/user/get_by_email', json={'email': 'test@gmail.com'}) assert response.status_code == 400 result = json.loads(response.data.decode()) assert result['code'] == 'validation_error' assert 'gmail.com is not valid for employee identities' in str(result['message']) @mock.patch('users.handlers.internal.Neo4jSession.__exit__') @mock.patch('users.handlers.internal.Neo4jSession.__enter__') @mock.patch('users.handlers.internal.identity_model') @mock.patch('users.utils.authorization.pdp_authorize_list_employees') @mock.patch('users.utils.api_utils.g', spec=['request_context']) def test_get_seat_users_with_plus_sign( mock_g: mock.MagicMock, authorization_mock: mock.MagicMock, identity_model_mock: mock.MagicMock, _enter_mock: mock.MagicMock, _exit_mock: mock.MagicMock, fixture_client: testing.FlaskClient, ) -> None: """Test get_seat_users endpoint with plus sign in search term.""" mock_g.request_context.jwt_identity_id = '74165b07-c597-46ba-b64a-21ff3632e843' authorization_mock.return_value = True identity_model_mock.get_employees_by_search_term.return_value = ['user1'] # Using query_string with dictionary handles encoding (space -> +, + -> %2B) # But to test literal plus we want to ensure it reaches the handler as '+' response = fixture_client.get('/internal/users', query_string={'term': 'foo+bar@sonymusic.com'}) assert response.status_code == 200 assert response.json == {'users': ['user1']} identity_model_mock.get_employees_by_search_term.assert_called_once_with( 'foo+bar@sonymusic.com' )