"""Unit tests for AssetUpload model.""" import datetime import os from unittest.mock import MagicMock from unittest.mock import patch from flask import g from oto import status import pytest from asset_transcoder.api import app from asset_transcoder.connectors import mysql from asset_transcoder.constants import asset_types as asset_type_const from asset_transcoder.constants import asset_upload as asset_upl_const from asset_transcoder.models import asset_status from asset_transcoder.models import asset_upload from asset_transcoder.models.asset_upload import AssetUpload from asset_transcoder.utils.asset_type import map_asset_to_file_types from asset_transcoder.utils.exceptions import OwsError from tests.utils import db_operations from tests.utils.db_operations import assets_upload_data def test_get_asset_upload(db_fixture): """Test asset_upload model returns data.""" fixture_asset = db_operations.assets_upload_data[0] result = asset_upload.get_asset_upload(filename=fixture_asset['filename']) assert result assert result.asset_upload_id == fixture_asset['id'] def test_get_asset_upload_not_found(db_fixture): """Test asset_upload model returns 404.""" filename = 'wrong_file_name' with pytest.raises(OwsError) as err: asset_upload.get_asset_upload(filename=filename) assert err.value.status == status.NOT_FOUND def test_create_asset_upload(empty_db_fixture): """Test asset_upload model creates row.""" payload = dict( user_id='alw:5', filename='my_unique_filename', object_id='111', object_type=asset_upl_const.OBJECT_TYPE_EPISODE, asset_type=asset_type_const.TYPE_FILE_JPG, original_filename='original_filname' ) result = asset_upload.create_asset_upload(payload) assert result assert result['filename'] == payload['filename'] assert isinstance(result['id'], int) def test_create_asset_upload_adupload(empty_db_fixture): """Test asset_upload model creates adupload object type.""" payload = dict( user_id='alw:5', filename='my_unique_filename', object_id='111', object_type=asset_upl_const.OBJECT_TYPE_ADUPLOAD, asset_type=asset_type_const.TYPE_FILE_MP3, original_filename='original_filname', ) result = asset_upload.create_asset_upload(payload) assert result assert result['filename'] == payload['filename'] assert isinstance(result['id'], int) def test_get_asset_status_without_final(empty_db_fixture): """Test asset_upload model return last status without finals.""" mocked_date = datetime.datetime(2018, 1, 1, 0) upload_payload = dict( user_id='alw:5', filename='my_unique_filename', object_id='111', object_type=asset_upl_const.OBJECT_TYPE_EPISODE, asset_type=asset_type_const.TYPE_FILE_JPG, created_date=mocked_date, updated_date=mocked_date, original_filename='original_filname', ) result = asset_upload.create_asset_upload(upload_payload) status_payload = dict( asset_upload_id=result['id'], status='encoding_route_complete', errors=None, created_date=mocked_date ) asset_status.create_asset_status(**status_payload) status_payload['status'] = 'encoding_processing' asset_status.create_asset_status(**status_payload) result_asset = asset_upload.get_objects_assets(['111'], ['episode']) assert result_asset['items'] == [{ 'id': result['id'], 'user_id': 'alw:5', 'asset_type': 'JPG', 'filename': 'my_unique_filename', 'object_id': '111', 'object_type': 'episode', 'original_filename': 'original_filname', 'created_date': mocked_date, 'updated_date': mocked_date, 'media_type': 'image', 'asset_finals': [], 'status': 'encoding_processing' }] def test_get_episode_assets(db_fixture): """Test that assets are being retrieved correctly.""" os.environ['OUTPUT_PODCAST_CDN'] = 'app.cdn.com' episode_id = 5 with pytest.raises(OwsError) as err: asset_upload.get_object_assets(episode_id, 'episode') assert err.value.status == status.NOT_FOUND episode_id = 2 result = asset_upload.get_object_assets(episode_id, 'episode') assert len(result['items']) == 2 artwork_asset = list(filter( lambda x: x['asset_type'] in asset_type_const.ASSET_JPG_FILE_TYPES, result['items'] ))[0] audio_asset = list(filter( lambda x: x['asset_type'] == asset_type_const.TYPE_FILE_WAV, result['items'] ))[0] assert artwork_asset == { 'id': 3, 'user_id': 'auth0-test-user-1', 'asset_type': 'JPG', 'filename': 'bucket_filename_3', 'object_id': '2', 'object_type': 'episode', 'original_filename': 'episode_photo_3.jpg', 'created_date': datetime.datetime(2018, 1, 1, 0, 0), 'updated_date': datetime.datetime(2018, 1, 1, 0, 0), 'media_type': 'image', 'asset_finals': [ dict( id=3, asset_type='JPG', asset_subtype='large_cover', filename='test_bucket_filename_3', url='https://app.cdn.com/test_bucket_filename_3', duration=0), dict( id=6, asset_type='JPG', asset_subtype='xlarge_cover', filename='test_bucket_filename_6', url='https://app.cdn.com/test_bucket_filename_6', duration=0 ) ], 'status': 'encoding_completed' } assert audio_asset == { 'id': 4, 'user_id': 'auth0-test-user-1', 'asset_type': 'WAV', 'filename': 'bucket_filename_4', 'object_id': '2', 'object_type': 'episode', 'original_filename': 'episode_2_audio.wav', 'created_date': datetime.datetime(2018, 1, 1, 0, 0), 'updated_date': datetime.datetime(2018, 1, 1, 0, 0), 'media_type': 'audio', 'asset_finals': [ dict( id=8, asset_type='DAT', asset_subtype=None, filename='test_bucket_filename_8', url='https://app.cdn.com/test_bucket_filename_8', duration=0 ), dict( id=7, asset_type='FLAC', asset_subtype=None, filename='test_bucket_filename_7', url='https://app.cdn.com/test_bucket_filename_7', duration=900 ), dict( id=4, asset_type='MP3', asset_subtype=None, filename='test_bucket_filename_4', url='https://app.cdn.com/test_bucket_filename_4', duration=900 ) ], 'status': 'encoding_completed' } @patch('asset_transcoder.utils.api_utils.asset_url') def test_get_objects_assets(url_mock, db_fixture): """Test that assets are being retrieved correctly.""" url_mock.return_value = 'http://cdn.com' episode_id = 2 podcast_id = 1 result = asset_upload.get_objects_assets([episode_id, podcast_id], ['episode', 'podcast']) assert len(result['items']) == 3 def test_create_asset_upload_commit_fails(db_fixture, monkeypatch): """Test that if commit fails exception would be thrown.""" mock_trans = MagicMock( commit=MagicMock( side_effect=AttributeError ) ) monkeypatch.setattr(mysql, 'asset_transcoder_db_session', MagicMock( return_value=mock_trans )) payload = dict( user_id='alw:5', filename='my_unique_filename', object_id='111', object_type=asset_upl_const.OBJECT_TYPE_EPISODE, asset_type=asset_type_const.TYPE_FILE_JPG, original_filename='original_filname', ) with pytest.raises(AttributeError): asset_upload.create_asset_upload(payload) def test_update_asset_upload_success(db_fixture): """Test that asset_upload is updated successfully.""" asset_upload_id = 1 new_object_id = '555' payload = dict( object_id=new_object_id ) updated = asset_upload.update_asset_upload(asset_upload_id, payload) assert updated assert updated['object_id'] == new_object_id def test_update_asset_upload_fail_not_found(db_fixture): """Test that asset_upload fails if not found.""" asset_upload_id = 555 payload = dict( object_id='555' ) with pytest.raises(OwsError) as err: asset_upload.update_asset_upload(asset_upload_id, payload) assert err.value.status == status.NOT_FOUND def test_update_asset_upload_fails_on_commit_error(db_fixture, monkeypatch): """Test that asset_upload fails on commit fails.""" mock_trans = MagicMock( commit=MagicMock( side_effect=AttributeError ) ) monkeypatch.setattr(mysql, 'asset_transcoder_db_session', MagicMock( return_value=mock_trans )) asset_upload_id = 1 new_object_id = '555' payload = dict( object_id=new_object_id ) with pytest.raises(AttributeError): asset_upload.update_asset_upload(asset_upload_id, payload) def test_delete_previous_assets(db_fixture): """ Create new asset_upload having existing one for the same object_type/object_id. It shall mark exising asset_upload entries as deleted """ existing_instance = assets_upload_data[0] new_instance = existing_instance.copy() object_id = new_instance['object_id'] object_type = new_instance['object_type'] asset_type = new_instance['asset_type'] assert object_id assert object_type assert asset_type new_instance.update({ 'id': '800', }) with mysql.transcoder_db_session() as session: session.execute(asset_upload.AssetUpload.__table__.insert().values([new_instance])) number_of_non_deleted = session.query(AssetUpload).filter_by( object_id=object_id, object_type=object_type, deleted=False).count() assert number_of_non_deleted == 2 with app.test_request_context(): g.log = MagicMock(exception=MagicMock()) asset_upload.delete_previous_assets( current_asset_upload_id=new_instance['id'], object_type=object_type, object_id=object_id, asset_type=asset_type ) number_of_non_deleted = session.query(AssetUpload).filter_by( object_id=object_id, object_type=object_type, deleted=False ).count() assert number_of_non_deleted == 1 old_instance = session.query(AssetUpload).filter(AssetUpload.asset_upload_id == existing_instance['id']).one() assert old_instance.deleted new_instance = session.query(AssetUpload).filter(AssetUpload.asset_upload_id == new_instance['id']).one() assert not new_instance.deleted def test_delete_other_by_file_types(db_fixture): """Test that we delete only uploads by file types.""" episode_id = 2 new_upload = dict( user_id='alw:1', asset_type='WAV', filename='bucket_filename_any_name', object_id=episode_id, object_type='episode', original_filename='episode_1_another_audio.wav', ) # we have 2 objects with episode=2 in db_operations.assets_upload_data upload_count = 2 with mysql.transcoder_db_session() as session: filters = [ (AssetUpload.object_id == episode_id), (AssetUpload.object_type == 'episode'), (AssetUpload.deleted.isnot(True)) ] current_assets = session.query(AssetUpload).filter(*filters).all() assert len(current_assets) == upload_count asset_1_file_types = map_asset_to_file_types(current_assets[0].to_dict()['asset_type']) asset_2_file_types = map_asset_to_file_types(current_assets[1].to_dict()['asset_type']) # check that uploads belong to different file types assert asset_1_file_types != asset_2_file_types new_asset_file_type = map_asset_to_file_types(new_upload['asset_type']) # check that new_upload belongs to one of 1 or 2 assert new_asset_file_type in (asset_1_file_types, asset_2_file_types) new_asset_upload = AssetUpload(**new_upload) session.add(new_asset_upload) session.flush() current_assets = session.query(AssetUpload).filter(*filters).all() # check that new upload was inserted assert len(current_assets) == upload_count + 1 with app.test_request_context(): g.log = MagicMock(exception=MagicMock()) asset_upload.delete_previous_assets( current_asset_upload_id=new_asset_upload.asset_upload_id, object_type=new_asset_upload.object_type, object_id=new_asset_upload.object_id, asset_type=new_asset_upload.asset_type ) current_assets = session.query(AssetUpload).filter(*filters).all() assert len(current_assets) == upload_count asset_1_file_types = map_asset_to_file_types(current_assets[0].to_dict()['asset_type']) asset_2_file_types = map_asset_to_file_types(current_assets[1].to_dict()['asset_type']) assert asset_1_file_types != asset_2_file_types def test_delete_asset_upload_success(db_fixture): """Test that asset_upload is deleted.""" asset_types = asset_type_const.IMAGE_FILE_TYPES object_id = '1' object_type = 'episode' with app.test_request_context(): g.log = MagicMock(exception=MagicMock()) asset = asset_upload.delete_asset_upload(asset_types, object_id, object_type) assert len(asset['items']) == 1 asset_filename = asset['items'][0]['filename'] with pytest.raises(OwsError) as err: asset_upload.get_asset_upload(asset_filename) assert err.value.status == status.NOT_FOUND def test_delete_asset_failed_not_found(db_fixture): """Test that asset_upload returns not found on deletion.""" asset_types = asset_type_const.AUDIO_FILE_TYPES object_id = '1' object_type = 'episode' with pytest.raises(OwsError) as err: asset_upload.delete_asset_upload(asset_types, object_id, object_type) assert err.value.status == status.NOT_FOUND def test_get_asset_by_id_and_type(db_fixture, asset_upload_wav_fixture): """Test asset_upload model returns data.""" result = asset_upload.get_asset_by_id_and_type(4, 'episode', ['WAV']) assert result['id'] == asset_upload_wav_fixture['id'] assert result['object_type'] == asset_upload_wav_fixture['object_type'] assert result['asset_type'] == asset_upload_wav_fixture['asset_type'] assert result['filename'] == asset_upload_wav_fixture['filename'] def test_get_asset_by_id_and_type_not_found(db_fixture): """Test asset_upload model returns 404.""" with pytest.raises(OwsError) as err: asset_upload.get_asset_by_id_and_type(1, 'episode', ['WAV']) assert err.value.status == status.NOT_FOUND def test_get_asset_by_id_and_type_not_encoded(db_fixture): """Test asset_upload model returns 404 for n.""" with pytest.raises(OwsError) as err: asset_upload.get_asset_by_id_and_type(2, 'episode', ['WAV']) assert err.value.status == status.NOT_FOUND def test_get_asset_by_id_and_type_podcast(db_fixture): """Test asset_upload model returns data.""" result = asset_upload.get_asset_by_id_and_type(1, 'podcast', ['TIF', 'JPG']) assert result['id'] == 2 assert result['object_type'] == 'podcast' assert result['asset_type'] == 'JPG' assert result['filename'] == db_operations.assets_upload_data[1]['filename'] def test_get_asset_by_id_and_type_not_found_podcast(db_fixture): """Test asset_upload model returns 404.""" with pytest.raises(OwsError) as err: asset_upload.get_asset_by_id_and_type(10, 'podcast', ['JPG']) assert err.value.status == status.NOT_FOUND def test_get_asset_by_id_and_type_not_encoded_podcast(db_fixture): """Test asset_upload model returns 404 for non encoded asset.""" with pytest.raises(OwsError) as err: asset_upload.get_asset_by_id_and_type(2, 'podcast', ['TIF', 'JPG']) assert err.value.status == status.NOT_FOUND def test_get_episodes_audio_assets_success(db_fixture): """Test that get_episodes_audio_assets return correct data.""" results = asset_upload.get_episodes_audio_assets([2, 4]) assert results == [ { 'id': 4, 'user_id': 'auth0-test-user-1', 'asset_type': 'WAV', 'filename': 'bucket_filename_4', 'object_id': '2', 'object_type': 'episode', 'created_date': datetime.datetime(2018, 1, 1, 0, 0), 'updated_date': datetime.datetime(2018, 1, 1, 0, 0), 'original_filename': 'episode_2_audio.wav', 'media_type': 'audio', 'asset_finals': [ { 'id': 8, 'asset_type': 'DAT', 'asset_subtype': None, 'filename': 'test_bucket_filename_8', 'url': 'https://app.cdn.com/test_bucket_filename_8', 'duration': 0 }, { 'id': 7, 'asset_type': 'FLAC', 'asset_subtype': None, 'filename': 'test_bucket_filename_7', 'url': 'https://app.cdn.com/test_bucket_filename_7', 'duration': 900 }, { 'id': 4, 'asset_type': 'MP3', 'asset_subtype': None, 'filename': 'test_bucket_filename_4', 'url': 'https://app.cdn.com/test_bucket_filename_4', 'duration': 900 } ] }, { 'id': 8, 'user_id': 'auth0-test-user-1', 'asset_type': 'WAV', 'filename': 'bucket_filename_8', 'object_id': '4', 'object_type': 'episode', 'created_date': datetime.datetime(2018, 1, 1, 0, 0), 'updated_date': datetime.datetime(2018, 1, 1, 0, 0), 'original_filename': 'episode_8_audio.wav', 'media_type': 'audio', 'asset_finals': [] } ]