"""Tests for Asset Upload logic tier.""" import os from unittest.mock import ANY from unittest.mock import call from unittest.mock import MagicMock from unittest.mock import patch from oto import status import pytest from asset_transcoder.constants import asset_types as asset_types_const from asset_transcoder.logic import asset_upload from asset_transcoder.models import asset_final as asset_final_model from asset_transcoder.models import asset_upload as asset_upload_model from asset_transcoder.utils import exceptions as exc from asset_transcoder.utils import s3 from tests.utils import db_operations def test_update_asset_upload_success( db_fixture, monkeypatch, asset_upload_fixture, get_user_fixture, mock_ownership_check): """Test that asset upload model is invoked.""" monkeypatch.setattr(asset_upload_model, 'update_asset_upload', MagicMock(return_value={ 'object_type': asset_upload_fixture['object_type'], 'object_id': asset_upload_fixture['object_id'], 'asset_type': asset_upload_fixture['asset_type'] })) monkeypatch.setattr(asset_upload_model, 'delete_previous_assets', MagicMock()) os.environ['OUTPUT_ASSETS_PODCAST_BUCKET_NAME'] = 'podcast-bucket-name' os.environ['PREVIEW_ASSETS_PODCAST_BUCKET_NAME'] = 'podcast-bucket-name' os.environ['ELASTIC_TRANSCODER_PODCAST_ID'] = 'podcast-elastic-transcoder-id' asset = db_operations.assets_upload_data[0] result = asset_upload.update_asset_upload(asset_upload_fixture) assert result['config'] == { 'output_bucket_name': 'podcast-bucket-name', 'preview_bucket_name': 'podcast-bucket-name', 'elastic_transcoder_id': 'podcast-elastic-transcoder-id' } asset_upload_model.update_asset_upload.assert_called_once_with(asset['id'], asset_upload_fixture) asset_upload_model.delete_previous_assets.assert_called_once_with( current_asset_upload_id=asset['id'], object_type=asset_upload_fixture['object_type'], object_id=asset_upload_fixture['object_id'], asset_type=asset_upload_fixture['asset_type'] ) def test_update_asset_upload_no_object_id_success( db_fixture, monkeypatch, asset_upload_fixture, get_user_fixture, mock_ownership_check): """Test that when you don't send object id it doesn't delete previous assets.""" monkeypatch.setattr(asset_upload_model, 'update_asset_upload', MagicMock(return_value={})) monkeypatch.setattr(asset_upload_model, 'delete_previous_assets', MagicMock()) asset_upload_fixture['object_id'] = None asset_upload.update_asset_upload(asset_upload_fixture) asset_upload_model.delete_previous_assets.assert_not_called def test_update_asset_upload_asset_not_found(db_fixture, get_user_fixture): """Test that asset_upload returns 404 if was not found by filename.""" payload = { 'filename': 'my_awesome_filename_5555', 'user_id': '1', 'asset_type': 'jpg' } with pytest.raises(exc.OwsError) as err: asset_upload.update_asset_upload(payload) assert err.value.status == status.NOT_FOUND def test_delete_asset_upload_success(db_fixture, monkeypatch, get_user_fixture, mock_ownership_check): """Test that asset_upload is deleted.""" frontend_asset_type = 'artwork' object_id = '1' object_type = 'episode' monkeypatch.setattr(asset_upload_model, 'delete_asset_upload', MagicMock(return_value=None)) asset_upload.delete_asset_upload(frontend_asset_type, object_id, object_type) asset_upload_model.delete_asset_upload.assert_called_once_with( asset_types_const.IMAGE_FILE_TYPES, object_id, object_type ) def test_delete_asset_upload_fail_not_found(db_fixture, get_user_fixture, mock_ownership_check): """Test that asset_upload is not deleted.""" frontend_asset_type = 'audio' object_id = '111' object_type = 'episode' with pytest.raises(exc.OwsError) as err: asset_upload.delete_asset_upload(frontend_asset_type, object_id, object_type) assert err.value.status == status.NOT_FOUND def test_update_asset_upload_asset_no_access(db_fixture, get_user_fixture): """Test that asset_upload returns 404 if was not found by filename.""" payload = { 'filename': 'bucket_filename_555', 'user_id': '1', 'asset_type': 'WAV', 'object_type': 'adupload', 'object_id': '3' } with pytest.raises(exc.OwsError) as err: asset_upload.update_asset_upload(payload) assert err.value.status == 404 def test_update_commit_splits_ext(db_fixture, get_user_fixture, monkeypatch, mock_ownership_check): """Test that commit splits the filename by extension so you can optionally pass it.""" monkeypatch.setattr(asset_upload_model, 'get_asset_upload', MagicMock()) monkeypatch.setattr(asset_upload, '_update_asset_upload', MagicMock()) monkeypatch.setattr(s3, 'update_file_metadata', MagicMock()) asset_upload.commit('cow.png', 1) asset_upload_model.get_asset_upload.assert_called_once_with('cow') s3.update_file_metadata.assert_called_once_with( 'cow.png', 'test-orcd-transcoder-input-bucket', {'Metadata': {'object_id': '1'}}) @patch('asset_transcoder.utils.s3.resource') @patch('asset_transcoder.utils.s3.client') def test_update_commit_success(s3_client, s3_resource, db_fixture, get_user_fixture, monkeypatch, mock_ownership_check): """Test that verifies that the object_id is saved back to the s3 file.""" s3_client.head_object.return_value = {'ContentType': 'audio/wav', 'Metadata': { 'asset_type': 'WAV', 'object_type': 'episode', }} s3_resource.meta.client.copy.return_value = True asset_upload.commit('bucket_filename_7.wav', 12345) s3_resource.meta.client.copy.assert_called_once_with( { 'Bucket': 'test-orcd-transcoder-input-bucket', 'Key': 'bucket_filename_7.wav' }, 'test-orcd-transcoder-input-bucket', 'bucket_filename_7.wav', ExtraArgs={ 'ContentType': 'audio/wav', 'Metadata': { 'asset_type': 'WAV', 'object_type': 'episode', 'object_id': '12345' }, 'MetadataDirective': 'REPLACE' }, SourceClient=s3_client ) def test_get_asset_by_id_and_type_success( db_fixture, monkeypatch, asset_upload_wav_fixture, get_user_fixture, mock_ownership_check): """Test get asset by id and type called.""" monkeypatch.setattr( asset_upload_model, 'get_asset_by_id_and_type', MagicMock(return_value=asset_upload_wav_fixture)) result = asset_upload.get_asset_by_id_and_type(4, 'episode', ['WAV']) assert result == asset_upload_wav_fixture @patch('asset_transcoder.utils.api_utils.get_user_id', return_value='test-uuid') def test_replicate_episodes_audio_assets(get_context_user_mock, episode_replication_fixture, monkeypatch): """Test replicate episodes audio assets.""" monkeypatch.setattr( asset_upload, '_replicate_episode_audio_assets_rows', MagicMock(return_value={'test': 'success'}) ) monkeypatch.setattr( asset_upload_model, 'get_episodes_audio_assets', MagicMock(return_value=[{'id': 1}]) ) result = asset_upload.replicate_episodes_audio_assets(episode_replication_fixture['objects']) asset_upload_model.get_episodes_audio_assets.assert_called_once_with([2, 8]) asset_upload._replicate_episode_audio_assets_rows.assert_has_calls([ call([{'id': 1}], 'test-uuid', {'original_episode_id': 2, 'episode_id': 123}), call([{'id': 1}], 'test-uuid', {'original_episode_id': 8, 'episode_id': 456}) ]) assert result['items'] == [{'test': 'success'}, {'test': 'success'}] @patch('asset_transcoder.models.asset_final.create_asset_final', return_value='asset_final') @patch('asset_transcoder.models.asset_status.create_asset_status', return_value='asset_status') @patch('asset_transcoder.connectors.mysql.asset_transcoder_db_session') def test_replicate_episode_audio_assets_rows( db_session_mock, create_asset_status_mock, create_asset_final_mock, episode_replication_fixture, full_assets_fixture, db_fixture, monkeypatch ): """Test replicate episodes audio assets rows.""" monkeypatch.setattr( asset_upload_model, 'create_asset_upload', MagicMock(return_value={'id': 10}) ) result = asset_upload._replicate_episode_audio_assets_rows( full_assets_fixture, 'auth0-test-user-1', episode_replication_fixture['objects'][1], ) asset_upload_model.create_asset_upload.assert_called_once_with( { 'user_id': 'auth0-test-user-1', 'asset_type': 'WAV', 'filename': 'uuid-filename-8', 'original_filename': 'test.wav', 'object_id': 456, 'object_type': 'episode', 'is_duplicated': True }, db_session_mock() ) create_asset_final_mock.assert_has_calls([ call( asset_upload_id=10, asset_type='MP3', asset_subtype=None, filename='test-uuid-mp3-2', duration=1200, session=db_session_mock() ), call( asset_upload_id=10, asset_type='FLAC', asset_subtype=None, filename='test-uuid-flac-2', duration=1180, session=db_session_mock() ), call( asset_upload_id=10, asset_type='DAT', asset_subtype=None, filename='test-uuid-dat-2', duration=0, session=db_session_mock() ) ]) create_asset_status_mock.assert_called_once_with( asset_upload_id=10, status='encoding_completed', created_date=ANY, errors=None, session=db_session_mock() ) assert result == { 'original_episode_id': 8, 'episode_id': 456, 'status': 'asset-replication-completed' } @patch('asset_transcoder.connectors.mysql.asset_transcoder_db_session') def test_replicate_episode_audio_assets_rows_asset_upload_not_found( db_session_mock, episode_replication_fixture, full_assets_fixture, db_fixture ): """Test replicate episodes audio assets rows asset upload not found.""" result = asset_upload._replicate_episode_audio_assets_rows( [], 'auth0-test-user-1', {'original_episode_id': 2222, 'episode_id': 123}, ) assert result == { 'original_episode_id': 2222, 'episode_id': 123, 'status': 'asset-replication-failed', 'error_message': 'Asset upload not found' } @patch('asset_transcoder.connectors.mysql.asset_transcoder_db_session') def test_replicate_episode_audio_assets_rows_asset_final_not_found( db_session_mock, episode_replication_fixture, full_assets_fixture, db_fixture ): """Test replicate episodes audio assets rows asset final not found.""" result = asset_upload._replicate_episode_audio_assets_rows( full_assets_fixture, 'auth0-test-user-1', {'original_episode_id': 2, 'episode_id': 123}, ) assert result == { 'original_episode_id': 2, 'episode_id': 123, 'status': 'asset-replication-failed', 'error_message': 'Final asset not found' } @patch('asset_transcoder.models.asset_final.create_asset_final', return_value='asset_final') @patch('asset_transcoder.models.asset_status.create_asset_status', return_value='asset_status') @patch('asset_transcoder.connectors.mysql.asset_transcoder_db_session') @patch('asset_transcoder.utils.api_utils.get_user_id', return_value='test-uuid') def test_replicate_podcast_artwork_assets(get_context_user_mock, db_session_mock, create_asset_status_mock, create_asset_final_mock, monkeypatch): """Test replicate podcast artwork assets.""" asset_by_id_and_type = { 'id': 1, 'asset_type': 'JPG', 'filename': 'assetfilename', 'original_filename': 'filename.jpg', 'object_type': 'podcast' } asset_finals = [ { 'asset_type': 'some_asset_type', 'asset_subtype': 'some_asset_subtype', 'filename': 'some_filename', 'duration': 0 } ] monkeypatch.setattr( asset_upload_model, 'get_asset_by_id_and_type', MagicMock(return_value=asset_by_id_and_type)) monkeypatch.setattr( asset_upload_model, 'create_asset_upload', MagicMock(return_value={'id': 10}) ) monkeypatch.setattr( asset_final_model, 'get_asset_finals', MagicMock(return_value={'items': asset_finals}) ) result = asset_upload.replicate_podcast_artwork_asset({ 'original_podcast_id': 1, 'podcast_id': 2 }) asset_upload_model.get_asset_by_id_and_type.assert_called_once_with(1, 'podcast', ['JPG']) asset_upload_model.create_asset_upload.assert_called_once_with( { 'user_id': 'test-uuid', 'asset_type': 'JPG', 'filename': 'assetfilename', 'original_filename': 'filename.jpg', 'object_id': 2, 'object_type': 'podcast', 'is_duplicated': True }, db_session_mock() ) asset_final_model.get_asset_finals.assert_called_once_with(1) create_asset_final_mock.assert_has_calls([ call( asset_upload_id=10, asset_type='some_asset_type', asset_subtype='some_asset_subtype', filename='some_filename', duration=0, session=db_session_mock() ) ]) create_asset_status_mock.assert_called_once_with( asset_upload_id=10, status='encoding_completed', created_date=ANY, errors=None, session=db_session_mock() ) assert result == {'original_podcast_id': 1, 'podcast_id': 2, 'status': 'asset-replication-completed'} @patch('asset_transcoder.connectors.mysql.asset_transcoder_db_session') def test_replicate_podcast_artwork_assets_asset_upload_not_found( db_session_mock, db_fixture ): """Test replicate podcast artwork assets asset upload not found.""" result = asset_upload.replicate_podcast_artwork_asset({ 'original_podcast_id': 9999, 'podcast_id': 99991 }) assert result == { 'original_podcast_id': 9999, 'podcast_id': 99991, 'status': 'asset-replication-failed' }