"""Test base FlowBase class.""" import datetime import json from unittest.mock import MagicMock from unittest.mock import patch from garcon import activity import pytest from feed_sender.flows import base @patch('garcon.activity.create') def test_flow_base_init(mock_activity, monkeypatch): """Test FlowBase init sets domain, name, version, activity properties.""" monkeypatch.setattr( base, 'get_domain', MagicMock(return_value='domain')) monkeypatch.setattr( base, 'generate_feed_name', MagicMock(return_value='feed_name')) flow = base.FlowBase('feed_name', '1.0') assert flow.domain == 'domain' assert flow.name == 'feed_name' assert flow.version == '1.0' assert mock_activity.call_count == 1 @patch('feed_sender.flows.base.get_domain') @patch('garcon.activity.create') def test_flow_base_workflow_id(mock_domain, mock_create, monkeypatch): """Test FlowBase workflow_id method.""" monkeypatch.setattr( base, 'generate_feed_name', MagicMock(return_value='feed_name')) flow = base.FlowBase('feed_name', '1.0') cur_dt = datetime.datetime.today().strftime('%Y-%m-%d') expected_result = 'feed_name-{date}'.format( date=cur_dt) assert flow.workflow_id({}) == expected_result assert flow.workflow_id({'context_date': '2016-01-01'}) == ( 'feed_name-2016-01-01') @patch('feed_sender.flows.base.get_domain') @patch('feed_sender.flows.base.generate_feed_name') @patch('garcon.activity.create') @patch('feed_sender.flows.base.logger') def test_flow_base_exception( mock_logging, mock_domain, mock_feed, mock_create): """Test FlowBase default on_exception logs to actor.logger.""" flow = base.FlowBase('feed_name', '1.0') # Non Activity calls FlowBase logger actor_mock = MagicMock() flow.on_exception(actor_mock, 'exception') mock_logging.error.assert_called_with('exception') # Assert Activity error calls activity's own logger activity_obj = activity.Activity() on_exception_mock = MagicMock() activity_obj.logger.error = on_exception_mock flow.on_exception(activity_obj, 'exception') on_exception_mock.assert_called_with('exception') @patch('feed_sender.flows.base.get_domain') @patch('feed_sender.flows.base.generate_feed_name') @patch('garcon.activity.create') def test_flow_base_decider(mock_domain, mock_feed, mock_create): """Test FlowBase decider throws not NotImplementedError.""" flow = base.FlowBase('feed_name', '1.0') with pytest.raises(NotImplementedError): flow.decider('schedule') def test_generate_feed_name(): """Test generating feed name.""" # valid feedname feed_name = 'feed_name' expected_result = 'feed_name_feed_sender' actual_result = base.generate_feed_name(feed_name) assert actual_result == expected_result # invalid feedname feed_name = 'feed_Name' with pytest.raises(AssertionError): base.generate_feed_name(feed_name) # invalid feedname feed_name = 'feed name' with pytest.raises(AssertionError): base.generate_feed_name(feed_name) def test_base_create_kwargs_collect_activity_for(): """Test create_kwargs_collect_activity_for method of FlowBase class.""" feed_name = 'test_feed' flow_version = '1.0' flow = base.FlowBase(feed_name, flow_version) # as supplied to Activity.run by garcon activity_input = { 'input': json.dumps({ 'key1': 'value1', 'namespace2.key2': 'value2', 'namespace3.key3': 'value3' }), 'activityId': 'activityId' } activity_with_kwargs = 'some_activity_accepting_kwargs' kwargs_collect_activity = flow.create_kwargs_collect_activity_for( activity_with_kwargs, mapping={ 'mapped_key2': 'namespace2.key2', 'mapped_key3': 'namespace3.key3', 'mapped_key4': 'key4' # not present in input context } ) output_context = {} def store_result(self, result): output_context['result'] = result expected_context = { 'some_activity_accepting_kwargs_kwargs.kwargs': { 'mapped_key2': 'value2', 'mapped_key3': 'value3', 'mapped_key4': None, } } with patch.multiple( activity.Activity, poll_for_activity=lambda self: activity_input, heartbeat=lambda self: None, complete=store_result): kwargs_collect_activity.run() assert json.loads(output_context['result']) == expected_context