"""Unit tests for contract_lifecycle endpoints.""" import datetime from unittest.mock import MagicMock, patch from flask.testing import FlaskClient from owsresponse import response import pytest from abacus_contract.constants.constants import CONTRACT_LIFECYCLE_STATUSES from abacus_contract.schemas.contract_lifecycle import ContractLifecycleDetailSchema from tests.utils.factories import ContractLifecycleFactory @patch('abacus_contract.blueprints.contract_lifecycle.logic') def test_get_contract_lifecycle_by_contract_id(mock_logic, fixture_client): """Test GET contract lifecycle by contract_id.""" mock_contract_lifecycle = ContractLifecycleFactory.create() contract_id = mock_contract_lifecycle.contract_id mock_logic.get_contract_lifecycle_by_contract_id.return_value =\ response.Response( message=ContractLifecycleDetailSchema().dump(mock_contract_lifecycle), status=200 ) res = fixture_client.get( f'/contract/{contract_id}/contract-lifecycle/' ) assert res.status_code == 200 mock_logic.get_contract_lifecycle_by_contract_id.assert_called_once_with( contract_id ) @pytest.mark.parametrize( [ 'standalone_check_result', 'get_account_id_result', 'pdp_auth_result', 'expected_status', ], [ pytest.param(True, 9, None, 200, id='Standalone check pass'), pytest.param(False, None, None, 404, id='Account not found'), pytest.param(False, 9, False, 403, id='PDP auth fail'), pytest.param(False, 9, True, 200, id='PDP auth pass'), ], ) @patch('abacus_contract.blueprints.contract_lifecycle.pdp_authorize_many_accounts') # noqa: E501 @patch('abacus_contract.blueprints.contract_lifecycle.contract_logic') @patch('abacus_contract.blueprints.contract_lifecycle.flask_request') def test_get_contract_lifecycle_by_contract_id_authorization( mock_flask_request: MagicMock, mock_contract_logic: MagicMock, mock_authorization: MagicMock, standalone_check_result: bool, get_account_id_result: int | None, pdp_auth_result: bool | None, expected_status: int, fixture_client: FlaskClient ): """Test authorization for getting contract lifecycle by contract_id.""" mock_flask_request.verify_rules_access_standalone.return_value =\ standalone_check_result mock_contract_logic.get_account_id_by_contract_id.return_value =\ get_account_id_result mock_authorization.return_value = pdp_auth_result contract_id = 1 res = fixture_client.get(f'/contract/{contract_id}/contract-lifecycle/') assert res.status_code == expected_status mock_flask_request.verify_rules_access_standalone.assert_called_once() if not standalone_check_result: mock_contract_logic.get_account_id_by_contract_id.assert_called_once_with( contract_id ) if get_account_id_result: mock_authorization.assert_called_once_with([get_account_id_result]) else: mock_authorization.assert_not_called() @pytest.mark.parametrize( ( 'profile_type', 'profile_role', 'authorize_return', 'expected_status', ), [ pytest.param( 'AbacusProfile', 'administrator', None, 200, id='standalone access' ), pytest.param( 'Account360Profile', 'account360', True, 200, id='pdp check, authorized' ), pytest.param( 'Account360Profile', 'account360', False, 403, id='pdp check, unauthorized' ), ], ) @patch('abacus_contract.blueprints.contract_lifecycle.pdp_authorize_many_accounts') @patch('abacus_contract.blueprints.contract_lifecycle.logic') @patch('abacus_contract.blueprints.contract_lifecycle.contract_logic') def test_get_contract_lifecycle_by_dataloaded_contract_id( mock_contract_logic: MagicMock, mock_logic: MagicMock, mock_authorize_many_accounts: MagicMock, fixture_client: FlaskClient, profile_type: str, profile_role: str, authorize_return: bool, expected_status: int ): """Get contract-lifecycle by dataloaded contract_ids.""" mock_contract_lifecycles = [ContractLifecycleFactory.create()] ids = [1, 2] mock_contract_logic.get_contracts_by_ids.return_value = [{'account_id': 1}] mock_logic.get_contract_lifecycles_by_contract_ids.return_value =\ response.Response( message=ContractLifecycleDetailSchema(many=True).dump( mock_contract_lifecycles ), status=200 ) if authorize_return is not None: mock_authorize_many_accounts.return_value = authorize_return res = fixture_client.post( '/contract/contract-lifecycle/dataloader', json=ids, headers={ 'Orchard-Requestor-Service': 'graphql-abacus', 'Orchard-Profile-Type': profile_type, 'Orchard-Profile-Id': '1234', 'Orchard-Roles': profile_role, 'Orchard-Identity-Id': '1234' } ) assert res.status_code == expected_status if expected_status == 200: mock_logic.get_contract_lifecycles_by_contract_ids.assert_called_once_with(ids) if authorize_return is not None: mock_authorize_many_accounts.assert_called_once_with([1]) else: mock_authorize_many_accounts.assert_not_called() @patch('abacus_contract.blueprints.contract_lifecycle.logic') def test_get_contract_lifecycles_by_ids(mock_logic, fixture_client): """Test GET contract lifecycles by ids.""" mock_contract_lifecycles = [ContractLifecycleFactory.create()] ids = [ mock_contract_lifecycles[0].contract_lifecycle_schedule_id ] mock_logic.get_contract_lifecycles_by_ids.return_value =\ response.Response( message=ContractLifecycleDetailSchema(many=True).dump( mock_contract_lifecycles ), status=200 ) res = fixture_client.post( '/contract-lifecycles/dataloader', json=ids ) assert res.status_code == 200 mock_logic.get_contract_lifecycles_by_ids.assert_called_once_with( ids ) @patch('abacus_contract.blueprints.contract_lifecycle.logic') def test_get_contract_lifecycle_by_schedule_id(mock_logic, fixture_client): """Test GET contract lifecycle by contract_lifecycle_schedule_id.""" mock_contract_lifecycle = ContractLifecycleFactory.create() contract_lifecycle_schedule_id = \ mock_contract_lifecycle.contract_lifecycle_schedule_id mock_logic.get_contract_lifecycle_by_schedule_id.return_value =\ response.Response( message=ContractLifecycleDetailSchema().dump(mock_contract_lifecycle), status=200 ) res = fixture_client.get( f'/contract-lifecycle-schedule/{contract_lifecycle_schedule_id}/contract-lifecycle/' # noqa: E501 ) assert res.status_code == 200 mock_logic.get_contract_lifecycle_by_schedule_id.assert_called_once_with( contract_lifecycle_schedule_id ) @patch('abacus_contract.blueprints.contract_lifecycle.logic') def test_create_contract_lifecycle(mock_logic, fixture_client): """Test creating contract_lifecycle.""" mock_contract_lifecycle = ContractLifecycleFactory.create() contract_id = mock_contract_lifecycle.contract_id schedule_id = mock_contract_lifecycle.contract_lifecycle_schedule_id lifecycle_term_start = datetime.date(2050, 12, 31) mock_post_request_payload = { 'lifecycle_term_start': str(lifecycle_term_start) } mock_logic.create_contract_lifecycle.return_value =\ response.Response( message='OK', status=201 ) res = fixture_client.post( f'/contract/{contract_id}/contract-lifecycle-schedule/{schedule_id}/contract-lifecycle/', # noqa: E501 json=mock_post_request_payload ) assert res.status_code == 201 mock_logic.create_contract_lifecycle.assert_called_once_with( contract_id=contract_id, contract_lifecycle_schedule_id=schedule_id, lifecycle_term_start=lifecycle_term_start ) @patch('abacus_contract.blueprints.contract_lifecycle.ContractLifecycle') @patch('abacus_contract.blueprints.contract_lifecycle.validate_pagination_params') def test_get_contract_lifecycles_to_be_renewed( mock_validate_pagination_params, mock_model, fixture_client ): """Test endpoint to get 'active' contract_lifecycle records to be renewed.""" pagination_params = {'limit': 100, 'offset': 0} contract_lifecycles = ContractLifecycleFactory.create_batch( 2, lifecycle_status=CONTRACT_LIFECYCLE_STATUSES.ACTIVE ) total_count = len(contract_lifecycles) mock_validate_pagination_params.return_value = pagination_params mock_model.get_by_renewal_effective.return_value = ( contract_lifecycles, total_count ) res = fixture_client.get('/contract-lifecycles/renewable/') assert res.status_code == 200 assert res.json['items'] assert res.json['total_count'] mock_model.get_by_renewal_effective.assert_called_once_with( pagination_params['limit'], pagination_params['offset'], datetime.date.today() ) @patch('abacus_contract.blueprints.contract_lifecycle.ContractLifecycle') @patch('abacus_contract.blueprints.contract_lifecycle.validate_pagination_params') def test_get_contract_lifecycles_to_be_terminated( mock_validate_pagination_params, mock_model, fixture_client ): """Test to get contract_lifecycle records to be terminated.""" pagination_params = {'limit': 100, 'offset': 0} contract_lifecycles = ContractLifecycleFactory.create_batch( 2, lifecycle_status=CONTRACT_LIFECYCLE_STATUSES.TO_BE_TERMINATED ) total_count = len(contract_lifecycles) mock_validate_pagination_params.return_value = pagination_params mock_model.get_by_termination_effective_or_collection_end.return_value = ( contract_lifecycles, total_count ) res = fixture_client.get('/contract-lifecycles/terminable/') assert res.status_code == 200 assert res.json['total_count'] == total_count mock_model.get_by_termination_effective_or_collection_end.assert_called_once_with( pagination_params['limit'], pagination_params['offset'], datetime.date.today() ) @patch('abacus_contract.blueprints.contract_lifecycle.ContractLifecycle') @patch('abacus_contract.blueprints.contract_lifecycle.validate_pagination_params') def test_get_contract_lifecycles_to_be_activated( mock_validate_pagination_params, mock_model, fixture_client ): """Test endpoint to get activable contract_lifecycle records.""" pagination_params = {'limit': 100, 'offset': 0} contract_lifecycles = ContractLifecycleFactory.create_batch( 2, lifecycle_status=CONTRACT_LIFECYCLE_STATUSES.INIT ) total_count = len(contract_lifecycles) mock_validate_pagination_params.return_value = pagination_params mock_model.get_by_activable.return_value = ( contract_lifecycles, total_count ) res = fixture_client.get('/contract-lifecycles/activable') assert res.status_code == 200 assert res.json['items'] assert res.json['total_count'] mock_model.get_by_activable.assert_called_once_with( pagination_params['limit'], pagination_params['offset'], datetime.date.today() ) @patch('abacus_contract.blueprints.contract_lifecycle.logic') def test_terminate_contract_lifecycles(mock_logic, fixture_client): """Test terminating contract lifecycles.""" contract_lifecycles = ContractLifecycleFactory.create_batch( 2, lifecycle_status=CONTRACT_LIFECYCLE_STATUSES.TO_BE_TERMINATED ) mock_post_request_payload = [ contract_lifecycle.contract_lifecycle_id for contract_lifecycle in contract_lifecycles ] mock_logic.terminate_contract_lifecycles.return_value =\ response.Response( message='OK', status=200 ) res = fixture_client.post( 'contract-lifecycles/terminate/', json=mock_post_request_payload ) assert res.status_code == 200 mock_logic.terminate_contract_lifecycles.assert_called_once_with( mock_post_request_payload ) @patch('abacus_contract.blueprints.contract_lifecycle.logic') def test_activate_contract_lifecycles(mock_logic, fixture_client): """Test activating contract lifecycles.""" contract_lifecycles = ContractLifecycleFactory.create_batch( 2, lifecycle_status=CONTRACT_LIFECYCLE_STATUSES.INIT ) mock_post_request_payload = [ contract_lifecycle.contract_lifecycle_id for contract_lifecycle in contract_lifecycles ] mock_logic.activate_contract_lifecycles.return_value = \ response.Response( message='OK', status=200 ) res = fixture_client.post( 'contract-lifecycles/activate/', json=mock_post_request_payload ) assert res.status_code == 200 mock_logic.activate_contract_lifecycles.assert_called_once_with( mock_post_request_payload ) @patch('abacus_contract.blueprints.contract_lifecycle.logic') def test_renew_contract_lifecycles(mock_logic, fixture_client): """Test renewing contract lifecycles.""" contract_lifecycles = ContractLifecycleFactory.create_batch( 2, lifecycle_status=CONTRACT_LIFECYCLE_STATUSES.ACTIVE ) mock_post_request_payload = [ contract_lifecycle.contract_lifecycle_id for contract_lifecycle in contract_lifecycles ] mock_logic.renew_contract_lifecycles.return_value =\ response.Response( message='OK', status=200 ) res = fixture_client.post( 'contract-lifecycles/renew/', json=mock_post_request_payload ) assert res.status_code == 200 mock_logic.renew_contract_lifecycles.assert_called_once_with( mock_post_request_payload )