from unittest.mock import ANY, MagicMock, patch from pandas import DataFrame from pytest import fixture, mark from laborious.activities.gates import Gates from sientia_do.notifications.models import NotificationLevel @fixture def gates(): return Gates( logger=MagicMock(), notification_handler=MagicMock() ) @mark.asyncio @patch('laborious.activities.gates.filter_functions') async def test_input_gate_specific_variables_null_values_with_stop_policy_only( filter_functions_mock, gates ): specific_variables_null_values_mock = MagicMock(return_value=True) empty_data_mock = MagicMock(return_value=False) def functions_side_effect(x): if x == 'SPECIFIC_VARIABLES_NULL_VALUES': return specific_variables_null_values_mock return empty_data_mock filter_functions_mock.__getitem__.side_effect = functions_side_effect input_data = { 'filters': { 'SPECIFIC_VARIABLES_NULL_VALUES': { 'POLICY': 'stop', 'VARIABLES': ['variable2'] } }, 'data': { 'variable': ['variable1', 'variable2'], 'value': [1, 2] } } result = await gates.input_gate(input_data) assert result == ('stop', -1) input_args = specific_variables_null_values_mock.call_args assert input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert input_args[0][1] == input_data['filters']['SPECIFIC_VARIABLES_NULL_VALUES'] empty_data_mock.assert_not_called() @mark.asyncio @patch('laborious.activities.gates.filter_functions') async def test_input_gate_specific_variables_null_values_with_continue_policy_only( filter_functions_mock, gates ): specific_variables_null_values_mock = MagicMock(return_value=True) empty_data_mock = MagicMock(return_value=False) def functions_side_effect(x): if x == 'SPECIFIC_VARIABLES_NULL_VALUES': return specific_variables_null_values_mock return empty_data_mock filter_functions_mock.__getitem__.side_effect = functions_side_effect input_data = { 'filters': { 'SPECIFIC_VARIABLES_NULL_VALUES': { 'POLICY': 'continue', 'VARIABLES': ['variable2'] } }, 'data': { 'variable': ['variable1', 'variable2'], 'value': [1, 2] } } result = await gates.input_gate(input_data) assert result == ('continue', 2) input_args = specific_variables_null_values_mock.call_args assert input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert input_args[0][1] == input_data['filters']['SPECIFIC_VARIABLES_NULL_VALUES'] empty_data_mock.assert_not_called() @mark.asyncio @patch('laborious.activities.gates.filter_functions') async def test_input_gate_specific_variables_null_values_no_filtered( filter_functions_mock, gates ): specific_variables_null_values_mock = MagicMock(return_value=False) empty_data_mock = MagicMock(return_value=False) def functions_side_effect(x): if x == 'SPECIFIC_VARIABLES_NULL_VALUES': return specific_variables_null_values_mock return empty_data_mock filter_functions_mock.__getitem__.side_effect = functions_side_effect input_data = { 'filters': { 'SPECIFIC_VARIABLES_NULL_VALUES': { 'POLICY': 'stop', 'VARIABLES': ['variable2'] } }, 'data': { 'variable': ['variable1', 'variable2'], 'value': [1, 2] } } result = await gates.input_gate(input_data) assert result == (None, 0) specific_variables_null_values_input_args = specific_variables_null_values_mock.call_args assert specific_variables_null_values_input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert specific_variables_null_values_input_args[0][ 1] == input_data['filters']['SPECIFIC_VARIABLES_NULL_VALUES'] empty_data_mock.assert_not_called() @mark.asyncio @patch('laborious.activities.gates.filter_functions') async def test_input_gate_one_stop_policy( filter_functions_mock, gates ): specific_variables_null_values_mock = MagicMock(return_value=True) empty_data_mock = MagicMock(return_value=True) def functions_side_effect(x): if x == 'SPECIFIC_VARIABLES_NULL_VALUES': return specific_variables_null_values_mock return empty_data_mock filter_functions_mock.__getitem__.side_effect = functions_side_effect input_data = { 'filters': { 'SPECIFIC_VARIABLES_NULL_VALUES': { 'POLICY': 'stop', 'VARIABLES': ['variable2'] }, 'EMPTY_DATA': { 'POLICY': 'continue', } }, 'data': { 'variable': ['variable1', 'variable2'], 'value': [1, 2] } } result = await gates.input_gate(input_data) assert result == ('stop', -1) specific_variables_null_values_input_args = specific_variables_null_values_mock.call_args assert specific_variables_null_values_input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert specific_variables_null_values_input_args[0][ 1] == input_data['filters']['SPECIFIC_VARIABLES_NULL_VALUES'] empty_data_input_args = empty_data_mock.call_args assert empty_data_input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert empty_data_input_args[0][1] == input_data['filters']['EMPTY_DATA'] @mark.asyncio @patch('laborious.activities.gates.filter_functions') async def test_input_gate_one_continue_policy( filter_functions_mock, gates ): specific_variables_null_values_mock = MagicMock(return_value=False) empty_data_mock = MagicMock(return_value=True) def functions_side_effect(x): if x == 'SPECIFIC_VARIABLES_NULL_VALUES': return specific_variables_null_values_mock return empty_data_mock filter_functions_mock.__getitem__.side_effect = functions_side_effect input_data = { 'filters': { 'SPECIFIC_VARIABLES_NULL_VALUES': { 'POLICY': 'stop', 'VARIABLES': ['variable2'] }, 'EMPTY_DATA': { 'POLICY': 'continue', } }, 'data': { 'variable': ['variable1', 'variable2'], 'value': [1, 2] } } result = await gates.input_gate(input_data) assert result == ('continue', 2) specific_variables_null_values_input_args = specific_variables_null_values_mock.call_args assert specific_variables_null_values_input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert specific_variables_null_values_input_args[0][ 1] == input_data['filters']['SPECIFIC_VARIABLES_NULL_VALUES'] empty_data_input_args = empty_data_mock.call_args assert empty_data_input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert empty_data_input_args[0][1] == input_data['filters']['EMPTY_DATA'] @mark.asyncio @patch('laborious.activities.gates.filter_functions') async def test_input_gate_no_filtered( filter_functions_mock, gates ): specific_variables_null_values_mock = MagicMock(return_value=False) empty_data_mock = MagicMock(return_value=False) def functions_side_effect(x): if x == 'SPECIFIC_VARIABLES_NULL_VALUES': return specific_variables_null_values_mock return empty_data_mock filter_functions_mock.__getitem__.side_effect = functions_side_effect input_data = { 'filters': { 'SPECIFIC_VARIABLES_NULL_VALUES': { 'POLICY': 'stop', 'VARIABLES': ['variable2'] }, 'EMPTY_DATA': { 'POLICY': 'continue', } }, 'data': { 'variable': ['variable1', 'variable2'], 'value': [1, 2] } } result = await gates.input_gate(input_data) assert result == (None, 0) specific_variables_null_values_input_args = specific_variables_null_values_mock.call_args assert specific_variables_null_values_input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) empty_data_input_args = empty_data_mock.call_args assert empty_data_input_args[0][0].equals(DataFrame( {'variable': ['variable1', 'variable2'], 'value': [1, 2]})) assert empty_data_input_args[0][1] == input_data['filters']['EMPTY_DATA'] @mark.asyncio @patch('laborious.activities.gates.filter_functions') async def test_input_gate_error( filter_functions_mock, gates ): filter_functions_mock.__getitem__.side_effect = KeyError('test') input_data = { 'filters': { 'SPECIFIC_VARIABLES_NULL_VALUES': { 'POLICY': 'stop', 'VARIABLES': ['variable2'] } }, 'data': { 'variable': ['variable1', 'variable2'], 'value': [1, 2] } } result = await gates.input_gate(input_data) assert result == (None, 0) gates.notification_handler.build_and_send_notification.assert_called_once_with( notification_id='INTPUT_GATE_ERROR__SPECIFIC_VARIABLES_NULL_VALUES', message="Error in filter SPECIFIC_VARIABLES_NULL_VALUES:{'POLICY': 'stop', 'VARIABLES': ['variable2']}: \n 'test'", block='input_gate', level=NotificationLevel.ERROR, attachment_content=ANY )