"""Unit tests for the release artist model.""" from unittest import mock from flask import g import pytest from product_digital.api import app from product_digital.connectors import mysql from product_digital.models import release_artist from product_digital.utils import error_handling from tests.factories.release_artist import ReleaseArtistFactory from tests.testutils import db @pytest.fixture def release_id(): """Return a fake release id.""" return 1234 @pytest.fixture def upc(): """Return a fake UPC.""" return 123456789012 @pytest.fixture def role(): """Return a fake role.""" return 'natural horn' @pytest.fixture def artist_names(): """Return a list of fake artist names.""" return ['Natural Horn Pete', 'Nadine The Natural Horn Wonder'] @pytest.fixture def release_artists(): """Return a list of fake release artist dicts.""" return [ { 'role': 'sousaphonist', 'artist_name': 'Sousaphone Bill' }, { 'role': 'harmonium player', 'artist_name': 'Henrietta Harmonium' } ] @pytest.fixture def release_artists_with_artist_info_id(release_artists): """Return a list of fake release artist dicts.""" return [ { 'artist_info_id': index, 'artist_name': artist['artist_name'], 'role': artist['role'] } for index, artist in enumerate(release_artists) ] def fetch_artists(release_id): """Fetch artists from the db by release and role.""" found_artists = [] with mysql.db_session() as session: query = session.query( release_artist.ReleaseArtist).filter_by(release_id=release_id) for artist in query: session.expunge(artist) found_artists.append(artist) return found_artists @db.test_schema def test_to_dict_properties(release_id, upc, role): """Test that the expected properties are returned.""" new_release_artist = release_artist.ReleaseArtist( release_id=release_id, upc=upc, role=role, artist_name='Charles Q.') db.seed_models(new_release_artist) assert new_release_artist.to_dict() == { 'release_artist_id': new_release_artist.release_artist_id, 'release_id': new_release_artist.release_id, 'upc': new_release_artist.upc, 'role': new_release_artist.role, 'artist_name': new_release_artist.artist_name, 'artist_info_id': new_release_artist.artist_info_id } @db.test_schema def test_save_for_release_id_new(release_id, upc, release_artists): """Test that new release artists are created with the given names.""" with app.test_request_context(): release_artist.save_for_release_id(release_id, upc, release_artists) found_artists = fetch_artists(release_id) assert len(found_artists) == 2 assert found_artists[0].role == release_artists[0].get('role') assert found_artists[0].artist_name == release_artists[0].get( 'artist_name') assert found_artists[0].upc == upc assert found_artists[1].role == release_artists[1].get('role') assert found_artists[1].artist_name == release_artists[1].get( 'artist_name') assert found_artists[1].upc == upc @db.test_schema def test_save_for_release_id_artist_removed(release_id, upc, release_artists): """Test that artists are deleted if they are not in the new list.""" guy_who_got_kicked_out = release_artist.ReleaseArtist( release_id=release_id, upc=upc, role='pan flautist', artist_name='Unwanted Jim') still_in_the_band = release_artist.ReleaseArtist( release_id=release_id, upc=upc, role=release_artists[0].get('role'), artist_name=release_artists[0].get('artist_name')) db.seed_models([guy_who_got_kicked_out, still_in_the_band]) with app.test_request_context(): release_artist.save_for_release_id(release_id, upc, release_artists) found_artists = fetch_artists(release_id) assert len(found_artists) == 2 assert found_artists[0].artist_name == release_artists[0].get( 'artist_name') assert found_artists[0].role == release_artists[0].get('role') assert found_artists[0].upc == upc assert found_artists[1].artist_name == release_artists[1].get( 'artist_name') assert found_artists[1].role == release_artists[1].get('role') assert found_artists[1].upc == upc @db.test_schema def test_save_for_release_id_artist_update(release_id, upc, release_artists): """Test an artist is updated if a release artist id is provided.""" artist_to_be_updated = release_artist.ReleaseArtist( artist_name='Identity Crisis', release_id=release_id, role='leader', upc=upc ) artist_to_be_removed = release_artist.ReleaseArtist( artist_name='Weakest Link', release_id=release_id, role='triangle', upc=upc ) db.seed_models([artist_to_be_updated, artist_to_be_removed]) release_artists = list(release_artists) artist_to_be_updated_dict = fetch_artists(release_id)[0].to_dict() artist_to_be_updated_dict['artist_name'] = '35 years old' release_artists.append(artist_to_be_updated_dict) with app.test_request_context(): release_artist.save_for_release_id(release_id, upc, release_artists) found_artists = fetch_artists(release_id) assert len(found_artists) == 3 updated_artist = found_artists[0] assert updated_artist.release_artist_id == artist_to_be_updated_dict['release_artist_id'] # noqa assert updated_artist.artist_name == artist_to_be_updated_dict['artist_name'] # noqa artist_a = { 'release_artist_id': 1, 'release_id': 1234, 'upc': 35, 'role': 'remixer', 'artist_name': 'abc', 'artist_info_id': 1234 } updated_artist_a = artist_a.copy() updated_artist_a['artist_info_id'] = 1236 artist_b = { 'release_artist_id': 2, 'release_id': 1234, 'upc': 35, 'role': 'composer', 'artist_name': 'def', 'artist_info_id': 1235 } @pytest.mark.parametrize( ( 'test_description', 'g_properties', 'expected_updated_artists', ), [( 'Test with g.is_non_destructive_update not set.', {}, [updated_artist_a], ), ( 'Test with g.is_non_destructive_update=True', {'is_non_destructive_update': True}, [updated_artist_a, artist_b], )]) @db.test_schema def test_save_for_release_id_artist_info_id_added( test_description, g_properties, expected_updated_artists, release_id, upc, release_artists, release_artists_with_artist_info_id ): """Test that artists can be given a new artist info id.""" existing_release_artist = ReleaseArtistFactory.build(**artist_a) another_existing_release_artist = ReleaseArtistFactory.build(**artist_b) db.seed_models([ existing_release_artist, another_existing_release_artist, ]) with app.test_request_context(): for key, value in g_properties.items(): setattr(g, key, value) release_artist.save_for_release_id( release_id, upc, [{'release_artist_id': 1, 'artist_info_id': 1236}] ) found_artists = [artist.to_dict() for artist in fetch_artists(release_id)] assert expected_updated_artists == found_artists @db.test_schema def test_save_for_release_id_response(release_id, upc, release_artists): """Test the contents of the response for a successful update.""" with app.test_request_context(): result = release_artist.save_for_release_id( release_id, upc, release_artists) assert result.status == 200 assert len(result.message) == 2 assert result.message[0].get('artist_name') == release_artists[0].get( 'artist_name') assert result.message[0].get('release_id') == release_id assert result.message[0].get('upc') == upc assert result.message[0].get('role') == release_artists[0].get('role') assert result.message[1].get('artist_name') == release_artists[1].get( 'artist_name') assert result.message[1].get('release_id') == release_id assert result.message[1].get('upc') == upc assert result.message[1].get('role') == release_artists[1].get('role') def test_save_for_release_id_db_error( db_exception, mocker, release_id, upc, release_artists): """Test that a DB exception is logged and a 500 status is returned.""" mock_session = db.mock_db_session(mocker) mock_session.query.side_effect = db_exception mocker.patch.object(error_handling, 'log_db_exception', mock.Mock()) with app.test_request_context(): result = release_artist.save_for_release_id( release_id, upc, release_artists) assert result.status == 500 error_handling.log_db_exception.assert_called_once_with(db_exception) @db.test_schema def test_get_release_artists_by_release_id_with_found_records( release_id, upc, role, artist_names): """Test that the release artists for the given release are returned.""" another_release_id = release_id + 47 wanted = [ release_artist.ReleaseArtist( release_id=release_id, upc=upc, role=role, artist_name='Joe Viletto'), release_artist.ReleaseArtist( release_id=release_id, upc=upc, role=role, artist_name='Charles Quirin')] unwanted = release_artist.ReleaseArtist( release_id=another_release_id, upc=upc, role=role, artist_name='Stank-Breath Pete') db.seed_models(wanted + [unwanted]) result = release_artist.get_release_artists_by_release_id(release_id) expected_message = [artist.to_dict() for artist in wanted] assert result.status == 200 assert result.message == expected_message @db.test_schema def test_get_release_artists_by_release_id_none_found( release_id, upc, role, artist_names): """Test that an empty list is returned if there are no records.""" result = release_artist.get_release_artists_by_release_id(release_id) assert result.status == 200 assert result.message == [] def test_get_release_artists_by_release_id_db_error( artist_names, db_exception, mocker, release_id, role, upc): """Test that a DB error is logged and 500 status is returned.""" mock_session = db.mock_db_session(mocker) mock_session.query.side_effect = db_exception mocker.patch.object(error_handling, 'log_db_exception', mock.Mock()) result = release_artist.get_release_artists_by_release_id(release_id) assert result.status == 500 error_handling.log_db_exception.assert_called_once_with(db_exception) @db.test_schema def test_delete(release_id, upc, role): """Test delete release artist for given product.""" new_release_artist = release_artist.ReleaseArtist( release_id=release_id, upc=upc, role=role, artist_name='Charles Q.') db.seed_models(new_release_artist) with mysql.db_session() as session: release_artist.delete(release_id, session) result = session.query(release_artist.ReleaseArtist).all() assert result == []