"""Refresh flow tests.""" from unittest.mock import call, MagicMock, patch import boto3 from garcon import activity import pytest from dim_refresh_etl.flows.refresh import flow as dimension_flow from dim_refresh_etl.util import environment def test_domain(monkeypatch): """Test domain is set by Flow appropriately.""" # if environment dev, domain is dev monkeypatch.setattr(dimension_flow.environment, 'name', 'dev') flow = dimension_flow.Flow() assert flow.domain == 'dev' # if environment is 'prod', domain is SWF_PROD_DOMAIN monkeypatch.setattr(dimension_flow.environment, 'name', environment.PROD) flow = dimension_flow.Flow() assert flow.domain == dimension_flow.SWF_PROD_DOMAIN @patch('dim_refresh_etl.util.sentry_utils.sentry_sdk') @patch('garcon.activity.create') @patch('dim_refresh_etl.flows.refresh.flow.logger') def test_flow_dimension_exception( mock_logging, mock_create, mock_sentry): """Test FlowBase default on_exception logs to actor.logger.""" flow = dimension_flow.Flow() # Non Activity calls FlowBase logger actor_mock = MagicMock() flow.on_exception(actor_mock, 'exception') mock_logging.error.assert_called_with('exception', exc_info=True) # Assert Activity error calls activity's own logger client = boto3.client('swf', 'us-east-1') activity_obj = activity.Activity(client) on_exception_mock = MagicMock() activity_obj.logger.error = on_exception_mock flow.on_exception(activity_obj, 'exception') on_exception_mock.assert_called_with('exception', exc_info=True) # Sentry called if DSN is an os var with patch.dict('os.environ', {'SENTRY_DSN': 'https://sentryblah.com'}): flow.on_exception(MagicMock(), 'exception') mock_sentry.assert_has_calls([call.capture_exception]) def test_workflow_id(): """Test workflow_id returns correct ID.""" flow = dimension_flow.Flow() id = flow.workflow_id({'dim_type': 'artist'}) # noqa assert id == 'artist' with pytest.raises(Exception): flow.workflow_id({'foo': 'bass'}) def test_source_schedule(): """Test appropriate source is loaded based on bootstrap.""" context = MagicMock() schedule = MagicMock() bootstrap = MagicMock() # works since we only care about bootstrap's return values schedule.return_value = bootstrap flow = dimension_flow.Flow() # test art_relations source activity is loaded bootstrap.result = { 'dim_refresh.source_db': 'art_relations'} flow.decider(schedule, context) assert any( 'export_mysql_source_table' in name for ( name, activity), _ in schedule.call_args_list) def test_downstream_flow(): """Test downstream activity called or not called dependent on context.""" context = {'downstream_contexts': None} schedule = MagicMock() bootstrap = MagicMock() # works since we only care about bootstrap's return values bootstrap.result = { 'dim_refresh.source_db': 'snowflake'} schedule.return_value = bootstrap flow = dimension_flow.Flow() # test downstream triggered with downstream_contexts flow.decider(schedule, context) assert any( 'downstream_dim_flows' in name for ( name, activity), _ in schedule.call_args_list) # test downstream not triggered wo/downstream_contexts schedule.reset_mock() flow.decider(schedule, context={}) assert not any( 'downstream_dim_flows' in name for ( name, activity), _ in schedule.call_args_list)