"""Unit tests for release correction logic.""" from flexmock import flexmock from oto import response from oto.response import create_not_found_response import pytest from product_workflow.logic import release_correction from product_workflow.models import ows_lyrics from product_workflow.models import ows_track from product_workflow.models \ import release_approval_queue as release_approval_queue_model from product_workflow.models \ import release_correction as release_correction_model from tests.factories import release_approval_queue \ as release_approval_queue_factory from tests.factories import release_correction as release_correction_factory from tests.testutils import db @pytest.fixture def release_approval_id(): """Create a release id for testing.""" return 123 @pytest.fixture def release_correction_id(): """Create a release correction id for testing.""" return 345 @pytest.fixture def get_last_release_correction_message(release_correction_id): """Return a dictionary of last release correction properties.""" return { 'release_correction_id': release_correction_id, 'status': 'active', 'items': [] } @pytest.fixture def get_last_release_correction_response(get_last_release_correction_message): """Return a release correction get message for testing.""" return response.Response(get_last_release_correction_message) @pytest.fixture def release_correction_properties(): """Return a dictionary of release correction properties for testing.""" return { 'release_id': 123, 'status': 'active', 'last_updated_by': 12345, 'last_updated_type': 'vendor'} @pytest.fixture def release_correction_create_message(): """Return the release correction create message properties for testing.""" return { 'release_correction_id': 1, 'release_id': 123, 'status': 'active'} @pytest.fixture def release_correction_create_response(release_correction_create_message): """Return a release correction create message for testing.""" return response.Response(release_correction_create_message, status=201) @pytest.fixture def release_correction_update_response(release_correction_create_message): """Return a response with status 200 for updates.""" return response.Response(release_correction_create_message, status=200) @pytest.fixture def db_error_response(): """Return a generic 400 level error response.""" return response.create_error_response( status=500, code='internal_error', message='something went wrong') @pytest.fixture def active_release_correction(): """Return a release correction model instance for testing.""" return release_correction_factory.ReleaseCorrectionFactory \ .build_batch(1, status='active')[0] @pytest.fixture def submitted_release_correction(): """Return a release correction model instance for testing.""" return release_correction_factory.ReleaseCorrectionFactory \ .build_batch(1, status='submitted')[0] @pytest.fixture def applied_release_correction(): """Return a release correction model instance for testing.""" return release_correction_factory.ReleaseCorrectionFactory \ .build_batch(1, status='applied')[0] @pytest.fixture def release_correction_delete_response(): """Return a release correction delete message for testing.""" return response.Response( dict(message='release correction deleted'), status=202) @pytest.fixture def rejected_approval_queue(): """Return a rejected release approval queue.""" return release_approval_queue_factory.ReleaseApprovalQueueFactory \ .build_batch(1, status='rejected')[0] @pytest.fixture def checked_in_approval_queue(): """Return a rejected release approval queue.""" return release_approval_queue_factory.ReleaseApprovalQueueFactory \ .build_batch(1, status='checked_in')[0] @pytest.fixture def mocked_session(mocker): """Mocked database session.""" return db.mock_db_session(mocker) def test_create_release_correction_success( release_correction_properties, release_correction_payload, release_correction_create_response, product_id, release_correction_create_message): """Test that create function is called and returns a 201 response.""" (flexmock(release_correction_model).should_receive( 'create').with_args( release_correction_properties).and_return( release_correction_create_response).once()) result = release_correction.create_release_correction_record( product_id, release_correction_payload) assert result.status == 201 assert result.message == release_correction_create_message def test_create_release_correction_failure( release_correction_properties, generic_error_response, product_id, release_correction_payload): """Test that model layer create function is called and 400 response.""" (flexmock(release_correction_model).should_receive( 'create').with_args(release_correction_properties).and_return( generic_error_response).once()) result = release_correction.create_release_correction_record( product_id, release_correction_payload) assert result.status == 400 assert result.errors == generic_error_response.errors def test_get_last_release_correction_success( release_approval_id, get_last_release_correction_response, get_last_release_correction_message): """Test that model layer get last function is called and 200 response.""" flexmock(release_correction_model) \ .should_receive('get_last_release_correction') \ .with_args(release_approval_id) \ .and_return(get_last_release_correction_response) \ .once() result = release_correction.get_last_correction(release_approval_id) assert result.status == 200 assert result.message == get_last_release_correction_message def test_get_last_release_correction_failure( release_approval_id, generic_error_response): """Test that model layer get last function is called and 400 response.""" flexmock(release_correction_model) \ .should_receive('get_last_release_correction') \ .with_args(release_approval_id) \ .and_return(generic_error_response) \ .once() result = release_correction.get_last_correction(release_approval_id) assert result.status == 400 assert result.errors == generic_error_response.errors def test_get_release_correction_success( release_correction_id, get_last_release_correction_response, get_last_release_correction_message): """Test model layer get correction function is called and 200 response.""" flexmock(release_correction_model) \ .should_receive('get_release_correction') \ .with_args(release_correction_id) \ .and_return(get_last_release_correction_response) \ .once() result = release_correction.get_correction(release_correction_id) assert result.status == 200 assert result.message == get_last_release_correction_message def test_get_release_correction_failure( release_correction_id, generic_error_response): """Test model layer get correction function is called and 400 response.""" flexmock(release_correction_model) \ .should_receive('get_release_correction') \ .with_args(release_correction_id) \ .and_return(generic_error_response) \ .once() result = release_correction.get_correction(release_correction_id) assert result.status == 400 assert result.errors == generic_error_response.errors def test_delete_correction_not_found(mocked_session, release_correction_id): """Test that model layer get correction is called and 404 response.""" flexmock(release_correction_model) \ .should_receive('get_correction_object') \ .with_args(mocked_session, release_correction_id) \ .and_return(None) \ .once() result = release_correction.delete_release_correction( release_correction_id) assert result.status == 404 def test_delete_correction_with_submitted_state( release_correction_id, submitted_release_correction, mocked_session): """Test model delete correction function is called and 400 response.""" flexmock(release_correction_model) \ .should_receive('get_correction_object') \ .with_args(mocked_session, release_correction_id) \ .and_return(submitted_release_correction) \ .once() result = release_correction.delete_release_correction( release_correction_id) assert result.status == 400 def test_delete_correction_with_applied_state( release_correction_id, applied_release_correction, mocked_session): """Test model delete correction function is called and 400 response.""" flexmock(release_correction_model) \ .should_receive('get_correction_object') \ .with_args(mocked_session, release_correction_id) \ .and_return(applied_release_correction) \ .once() result = release_correction.delete_release_correction( release_correction_id) assert result.status == 400 def test_delete_correction_with_active_status_success( release_correction_id, active_release_correction, mocked_session): """Test that model layer delete correction is called and 202 response.""" flexmock(release_correction_model) \ .should_receive('get_correction_object') \ .with_args(mocked_session, release_correction_id) \ .and_return(active_release_correction) \ .once() flexmock(release_approval_queue_model) \ .should_receive('get_approval_for_correction') \ .with_args(mocked_session, release_correction_id) \ .and_return(None) \ .once() result = release_correction.delete_release_correction( release_correction_id) assert result.status == 202 def test_delete_correction_with_active_status_and_rejected_approval( release_correction_id, active_release_correction, rejected_approval_queue, mocked_session): """Test that model layer delete correction is called and 202 response.""" flexmock(release_correction_model) \ .should_receive('get_correction_object') \ .with_args(mocked_session, release_correction_id) \ .and_return(active_release_correction) \ .once() flexmock(release_approval_queue_model) \ .should_receive('get_approval_for_correction') \ .with_args(mocked_session, release_correction_id) \ .and_return(rejected_approval_queue) \ .once() result = release_correction.delete_release_correction( release_correction_id) assert result.status == 202 def test_delete_correction_with_active_status_and_checked_in_approval( release_correction_id, active_release_correction, checked_in_approval_queue, mocked_session): """Test that model layer delete correction is called and 400 response.""" flexmock(release_correction_model) \ .should_receive('get_correction_object') \ .with_args(mocked_session, release_correction_id) \ .and_return(active_release_correction) \ .once() flexmock(release_approval_queue_model) \ .should_receive('get_approval_for_correction') \ .with_args(mocked_session, release_correction_id) \ .and_return(checked_in_approval_queue) \ .once() result = release_correction.delete_release_correction( release_correction_id) assert result.status == 400 def test_update_release_correction_record_success( release_correction_id, release_correction_update_response ): """Test that a successful update returns a 200 response.""" changed_props = {'status': 'submitted'} ( flexmock(release_correction_model) .should_receive('update') .with_args(release_correction_id, changed_props) .and_return(release_correction_update_response) .once() ) result = release_correction.update_release_correction_record( release_correction_id, changed_props ) assert result.status == 200 def test_update_release_correction_record_failure(release_correction_id): """Test that unsuccessful update passes the status code.""" changed_props = {'status': 'submitted'} not_found_response = create_not_found_response('not found') ( flexmock(release_correction_model) .should_receive('update') .with_args(release_correction_id, changed_props) .and_return(not_found_response) .once() ) result = release_correction.update_release_correction_record( release_correction_id, changed_props ) assert result.status == not_found_response.status def test_get_lyrics_by_product_id_success( product_id, get_lyrics_in_correction_response, get_tracks_by_product_id_response, get_lyrics_by_track_ids_response, get_lyrics_by_product_id_response): """Test get_lyrics_by_product_id function is called and 200 response.""" flexmock(release_correction) \ .should_receive('get_lyrics_in_correction') \ .with_args(product_id) \ .and_return(get_lyrics_in_correction_response) \ .once() flexmock(ows_track) \ .should_receive('get_tracks_by_product_id') \ .with_args(product_id) \ .and_return( response.Response(message=get_tracks_by_product_id_response)) \ .once() track_ids = {2, 3} flexmock(ows_lyrics) \ .should_receive('get_lyrics_by_track_ids') \ .with_args(track_ids) \ .and_return( response.Response(message=get_lyrics_by_track_ids_response)) \ .once() result = release_correction.get_lyrics_by_product_id(product_id) assert result.status == 200 assert result.message == get_lyrics_by_product_id_response def test_get_lyrics_by_product_id_failure( product_id, get_lyrics_by_product_id_response): """Test get_lyrics_by_product_id function is called and 500 response.""" flexmock(release_correction) \ .should_receive('get_lyrics_in_correction') \ .with_args(product_id) \ .and_return(response.create_fatal_response()) \ .once() result = release_correction.get_lyrics_by_product_id(product_id) assert result.status == 500 def test_get_lyrics_by_product_id_not_found( product_id, get_tracks_by_product_id_no_tracks_response, get_lyrics_by_product_id_not_found_response): """Test get_lyrics_by_product_id function is called and 404 response.""" flexmock(release_correction) \ .should_receive('get_lyrics_in_correction') \ .with_args(product_id) \ .and_return(create_not_found_response( message='No release correction record found')) \ .once() flexmock(ows_track) \ .should_receive('get_tracks_by_product_id') \ .with_args(product_id) \ .and_return( response.Response( message=get_tracks_by_product_id_no_tracks_response)).once() result = release_correction.get_lyrics_by_product_id(product_id) assert result.status == 404 assert result.errors == get_lyrics_by_product_id_not_found_response def test_get_lyrics_in_correction_success( product_id, get_last_release_correction_response_for_lyrics, get_lyrics_in_correction_response): """Test get_lyrics_in_correction function when success.""" flexmock(release_correction_model) \ .should_receive('get_last_release_correction') \ .with_args(product_id) \ .and_return(get_last_release_correction_response_for_lyrics) \ .once() result = release_correction.get_lyrics_in_correction(product_id) assert result == get_lyrics_in_correction_response def test_get_lyrics_in_correction_not_found( product_id, get_last_release_correction_response, get_lyrics_in_correction_not_found_response): """Test get_lyrics_in_correction function when success.""" flexmock(release_correction_model) \ .should_receive('get_last_release_correction') \ .with_args(product_id) \ .and_return(get_last_release_correction_response) \ .once() result = release_correction.get_lyrics_in_correction(product_id) assert result.status == 404 assert result.message == \ get_lyrics_in_correction_not_found_response.message def test_get_lyrics_by_track_id_correction_success( product_id, track_id, get_lyrics_in_correction_for_single_track_response, get_lyrics_by_track_id_response): """Test get_lyrics_by_track_id function is called and 200 response.""" flexmock(release_correction) \ .should_receive('get_lyrics_in_correction') \ .with_args(product_id, track_id) \ .and_return(get_lyrics_in_correction_for_single_track_response) \ .once() result = release_correction.get_lyrics_by_track_id(product_id, track_id) assert result.status == 200 assert result.message == get_lyrics_by_track_id_response def test_get_lyrics_by_track_id_ows_lyrics_success( product_id, track_id, get_lyrics_by_track_id_response, get_lyrics_by_track_ids_response_for_single_track): """Test get_lyrics_by_track_id function is called and 200 response.""" flexmock(release_correction) \ .should_receive('get_lyrics_in_correction') \ .with_args(product_id, track_id) \ .and_return(create_not_found_response( message='No release correction record found')) \ .once() flexmock(ows_lyrics) \ .should_receive('get_lyrics_by_track_ids') \ .with_args([track_id]) \ .and_return( response.Response( message=get_lyrics_by_track_ids_response_for_single_track)) \ .once() result = release_correction.get_lyrics_by_track_id(product_id, track_id) assert result.status == 200 assert result.message == get_lyrics_by_track_id_response def test_get_lyrics_by_track_id_failure(product_id, track_id): """Test get_lyrics_by_track_id function is called and 500 response.""" flexmock(release_correction) \ .should_receive('get_lyrics_in_correction') \ .with_args(product_id, track_id) \ .and_return(response.create_fatal_response()) \ .once() result = release_correction.get_lyrics_by_track_id(product_id, track_id) assert result.status == 500 def test_get_lyrics_by_track_id_not_found( product_id, track_id, get_lyrics_by_track_ids_not_found_response, get_lyrics_by_track_id_not_found_response): """Test get_lyrics_by_track_id function is called and 404 response.""" flexmock(release_correction) \ .should_receive('get_lyrics_in_correction') \ .with_args(product_id, track_id) \ .and_return(create_not_found_response( message='No release correction record found')) \ .once() flexmock(ows_lyrics) \ .should_receive('get_lyrics_by_track_ids') \ .with_args([track_id]) \ .and_return(create_not_found_response( message=get_lyrics_by_track_id_not_found_response)) \ .once() result = release_correction.get_lyrics_by_track_id(product_id, track_id) assert result.status == 404 assert result.errors == get_lyrics_by_track_id_not_found_response def test_get_lyrics_in_correction_for_track_success( product_id, get_last_release_correction_response_for_lyrics, get_lyrics_in_correction_response): """Test get_lyrics_in_correction function with track_id when success.""" flexmock(release_correction_model) \ .should_receive('get_last_release_correction') \ .with_args(product_id) \ .and_return(get_last_release_correction_response_for_lyrics) \ .once() track_id = 1 result = release_correction.get_lyrics_in_correction(product_id, track_id) assert result == get_lyrics_in_correction_response[0]